File: src\libraries\Common\src\System\Net\SocketAddressPal.Unix.cs
Web Access
Project: src\src\libraries\System.Net.Sockets\src\System.Net.Sockets.csproj (System.Net.Sockets)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Diagnostics;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
 
namespace System.Net
{
    internal static class SocketAddressPal
    {
        public static readonly int IPv4AddressSize;
        public static readonly int IPv6AddressSize;
        public static readonly int UdsAddressSize;
        public static readonly int MaxAddressSize;
 
#pragma warning disable CA1810
        static unsafe SocketAddressPal()
        {
            int ipv4 = 0;
            int ipv6 = 0;
            int uds = 0;
            int max = 0;
            Interop.Error err = Interop.Sys.GetSocketAddressSizes(&ipv4, &ipv6, &uds, &max);
            Debug.Assert(err == Interop.Error.SUCCESS, $"Unexpected err: {err}");
            Debug.Assert(ipv4 > 0);
            Debug.Assert(ipv6 > 0);
            Debug.Assert(uds > 0);
            Debug.Assert(max >= ipv4 && max >= ipv6 && max >= uds);
            IPv4AddressSize = ipv4;
            IPv6AddressSize = ipv6;
            UdsAddressSize = uds;
            MaxAddressSize = max;
        }
#pragma warning restore CA1810
 
        private static void ThrowOnFailure(Interop.Error err)
        {
            switch (err)
            {
                case Interop.Error.SUCCESS:
                    return;
 
                case Interop.Error.EFAULT:
                    // The buffer was either null or too small.
                    throw new IndexOutOfRangeException();
 
                case Interop.Error.EAFNOSUPPORT:
                    // There was no appropriate mapping from the platform address family.
                    throw new PlatformNotSupportedException();
 
                default:
                    Debug.Fail("Unexpected failure in GetAddressFamily");
                    throw new PlatformNotSupportedException();
            }
        }
 
        public static unsafe AddressFamily GetAddressFamily(ReadOnlySpan<byte> buffer)
        {
            AddressFamily family;
            Interop.Error err;
            fixed (byte* rawAddress = buffer)
            {
                err = Interop.Sys.GetAddressFamily(rawAddress, buffer.Length, (int*)&family);
            }
 
            ThrowOnFailure(err);
            return family;
        }
 
        public static unsafe void SetAddressFamily(Span<byte> buffer, AddressFamily family)
        {
            Interop.Error err;
 
            if (family != AddressFamily.Unknown)
            {
                fixed (byte* rawAddress = buffer)
                {
                    err = Interop.Sys.SetAddressFamily(rawAddress, buffer.Length, (int)family);
                }
 
                ThrowOnFailure(err);
            }
        }
 
        public static unsafe ushort GetPort(ReadOnlySpan<byte> buffer)
        {
            ushort port;
            Interop.Error err;
            fixed (byte* rawAddress = buffer)
            {
                err = Interop.Sys.GetPort(rawAddress, buffer.Length, &port);
            }
 
            ThrowOnFailure(err);
            return port;
        }
 
        public static unsafe void SetPort(Span<byte> buffer, ushort port)
        {
            Interop.Error err;
            fixed (byte* rawAddress = buffer)
            {
                err = Interop.Sys.SetPort(rawAddress, buffer.Length, port);
            }
 
            ThrowOnFailure(err);
        }
 
        public static unsafe uint GetIPv4Address(ReadOnlySpan<byte> buffer)
        {
            uint ipAddress;
            Interop.Error err;
            fixed (byte* rawAddress = &MemoryMarshal.GetReference(buffer))
            {
                err = Interop.Sys.GetIPv4Address(rawAddress, buffer.Length, &ipAddress);
            }
 
            ThrowOnFailure(err);
            return ipAddress;
        }
 
        public static unsafe void GetIPv6Address(ReadOnlySpan<byte> buffer, Span<byte> address, out uint scope)
        {
            uint localScope;
            Interop.Error err;
            fixed (byte* rawAddress = &MemoryMarshal.GetReference(buffer))
            fixed (byte* ipAddress = &MemoryMarshal.GetReference(address))
            {
                err = Interop.Sys.GetIPv6Address(rawAddress, buffer.Length, ipAddress, address.Length, &localScope);
            }
 
            ThrowOnFailure(err);
            scope = localScope;
        }
 
        public static unsafe void SetIPv4Address(Span<byte> buffer, uint address)
        {
            Interop.Error err;
            fixed (byte* rawAddress = buffer)
            {
                err = Interop.Sys.SetIPv4Address(rawAddress, buffer.Length, address);
            }
 
            ThrowOnFailure(err);
        }
 
        public static unsafe void SetIPv4Address(Span<byte> buffer, byte* address)
        {
            uint addr = (uint)System.Runtime.InteropServices.Marshal.ReadInt32((IntPtr)address);
            SetIPv4Address(buffer, addr);
        }
 
        public static unsafe void SetIPv6Address(Span<byte> buffer, Span<byte> address, uint scope)
        {
 
            fixed (byte* rawInput = &MemoryMarshal.GetReference(address))
            {
                SetIPv6Address(buffer, rawInput, address.Length, scope);
            }
        }
 
        public static unsafe void SetIPv6Address(Span<byte> buffer, byte* address, int addressLength, uint scope)
        {
            Interop.Error err;
            fixed (byte* rawAddress = buffer)
            {
                err = Interop.Sys.SetIPv6Address(rawAddress, buffer.Length, address, addressLength, scope);
            }
 
            ThrowOnFailure(err);
        }
 
        public static void Clear(Span<byte> buffer)
        {
            AddressFamily family = GetAddressFamily(buffer);
            buffer.Clear();
            // platforms where this matters (OSXLike & BSD) use uint8 for SA length
            buffer[0] = (byte)Math.Min(buffer.Length, 255);
            SetAddressFamily(buffer, family);
        }
    }
}