File: src\Shared\HttpSys\NativeInterop\SocketAddress.cs
Web Access
Project: src\src\Servers\HttpSys\src\Microsoft.AspNetCore.Server.HttpSys.csproj (Microsoft.AspNetCore.Server.HttpSys)
// 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.Contracts;
using System.Net;
using System.Net.Sockets;
 
namespace Microsoft.AspNetCore.HttpSys.Internal;
 
internal sealed class SocketAddress
{
    private const int NumberOfIPv6Labels = 8;
    private const int IPv6AddressSize = 28;
    private const int IPv4AddressSize = 16;
    private const int WriteableOffset = 2;
 
    private readonly byte[] _buffer;
    private readonly int _size;
 
    private SocketAddress(AddressFamily family, int size)
    {
        ArgumentOutOfRangeException.ThrowIfLessThan(size, WriteableOffset);
        Family = family;
        _size = size;
        // Sized to match the native structure
        _buffer = new byte[((size / IntPtr.Size) + 2) * IntPtr.Size]; // sizeof DWORD
    }
 
    internal AddressFamily Family { get; }
 
    internal int GetPort()
    {
        return (_buffer[2] << 8 & 0xFF00) | (_buffer[3]);
    }
 
    internal IPAddress? GetIPAddress()
    {
        if (Family == AddressFamily.InterNetworkV6)
        {
            return GetIpv6Address();
        }
        else if (Family == AddressFamily.InterNetwork)
        {
            return GetIPv4Address();
        }
        else
        {
            return null;
        }
    }
 
    private IPAddress GetIpv6Address()
    {
        Contract.Assert(_size >= IPv6AddressSize);
        var bytes = new byte[NumberOfIPv6Labels * 2];
        Array.Copy(_buffer, 8, bytes, 0, NumberOfIPv6Labels * 2);
        return new IPAddress(bytes); // TODO: Does scope id matter?
    }
 
    private IPAddress GetIPv4Address()
    {
        Contract.Assert(_size >= IPv4AddressSize);
        return new IPAddress(new byte[] { _buffer[4], _buffer[5], _buffer[6], _buffer[7] });
    }
 
    internal static unsafe SocketAddress? CopyOutAddress(IntPtr address)
    {
        var addressFamily = *((ushort*)address);
        if (addressFamily == (ushort)AddressFamily.InterNetwork)
        {
            var v4address = new SocketAddress(AddressFamily.InterNetwork, IPv4AddressSize);
            fixed (byte* pBuffer = v4address._buffer)
            {
                for (var index = 2; index < IPv4AddressSize; index++)
                {
                    pBuffer[index] = ((byte*)address)[index];
                }
            }
            return v4address;
        }
        if (addressFamily == (ushort)AddressFamily.InterNetworkV6)
        {
            var v6address = new SocketAddress(AddressFamily.InterNetworkV6, IPv6AddressSize);
            fixed (byte* pBuffer = v6address._buffer)
            {
                for (var index = 2; index < IPv6AddressSize; index++)
                {
                    pBuffer[index] = ((byte*)address)[index];
                }
            }
            return v6address;
        }
 
        return null;
    }
}