using System; using System.Runtime.InteropServices; using Vanara.Extensions; using Vanara.InteropServices; namespace Vanara.PInvoke { public static partial class Ws2_32 { [PInvokeData("winsock2.h")] public enum ADDRESS_FAMILY : ushort { /// Unspecified address family. AF_UNSPEC = 0, /// Unix local to host address. AF_UNIX = 1, /// Address for IP version 4. AF_INET = 2, /// ARPANET IMP address. AF_IMPLINK = 3, /// Address for PUP protocols. AF_PUP = 4, /// Address for MIT CHAOS protocols. AF_CHAOS = 5, /// Address for Xerox NS protocols. AF_NS = 6, /// IPX or SPX address. AF_IPX = AF_NS, /// Address for ISO protocols. AF_ISO = 7, /// Address for OSI protocols. AF_OSI = AF_ISO, /// European Computer Manufacturers Association (ECMA) address. AF_ECMA = 8, /// Address for Datakit protocols. AF_DATAKIT = 9, /// Addresses for CCITT protocols, such as X.25. AF_CCITT = 10, /// IBM SNA address. AF_SNA = 11, /// DECnet address. AF_DECnet = 12, /// Direct data-link interface address. AF_DLI = 13, /// LAT address. AF_LAT = 14, /// NSC Hyperchannel address. AF_HYLINK = 15, /// AppleTalk address. AF_APPLETALK = 16, /// NetBios address. AF_NETBIOS = 17, /// VoiceView address. AF_VOICEVIEW = 18, /// FireFox address. AF_FIREFOX = 19, /// Undocumented. AF_UNKNOWN1 = 20, /// Banyan address. AF_BAN = 21, /// Native ATM services address. AF_ATM = 22, /// Address for IP version 6. AF_INET6 = 23, /// Address for Microsoft cluster products. AF_CLUSTER = 24, /// IEEE 1284.4 workgroup address. AF_12844 = 25, /// IrDA address. AF_IRDA = 26, /// Address for Network Designers OSI gateway-enabled protocols. AF_NETDES = 28, /// Undocumented. AF_TCNPROCESS = 29, /// Undocumented. AF_TCNMESSAGE = 30, /// Undocumented. AF_ICLFXBM = 31, /// Bluetooth RFCOMM/L2CAP protocols. AF_BTH = 32, /// Link layer interface. AF_LINK = 33, /// Windows Hyper-V. AF_HYPERV = 34, } /// The IN_ADDR structure represents an IPv4 address. [PInvokeData("winsock2.h")] [StructLayout(LayoutKind.Sequential)] public struct IN_ADDR { /// An IPv4 address formatted as a u_long. public uint S_addr; /// Initializes a new instance of the struct. /// An IPv4 address. public IN_ADDR(uint v4addr) => S_addr = v4addr; /// Initializes a new instance of the struct. /// An IPv4 address /// Byte array must have 4 items. - v4addr public IN_ADDR(byte[] v4addr) { if (v4addr == null && v4addr.Length != 4) throw new ArgumentException("Byte array must have 4 items.", nameof(v4addr)); S_addr = BitConverter.ToUInt32(v4addr, 0); } /// Initializes a new instance of the struct. /// The first byte. /// The second byte. /// The third byte. /// The fourth byte. public IN_ADDR(byte b1, byte b2, byte b3, byte b4) => S_addr = b1 | (uint)b2 << 8 | (uint)b3 << 16 | (uint)b4 << 24; /// Gets the address represented as four bytes. /// An IPv4 address formatted as four u_chars. public byte[] S_un_b => BitConverter.GetBytes(S_addr); /// Performs an implicit conversion from to . /// An IN_ADDR value. /// The result of the conversion. public static implicit operator uint(IN_ADDR a) => a.S_addr; /// Performs an implicit conversion from to . /// An IN_ADDR value. /// The result of the conversion. public static implicit operator long(IN_ADDR a) => a.S_addr; /// Performs an implicit conversion from to . /// An IN_ADDR value. /// The result of the conversion. public static implicit operator byte[] (IN_ADDR a) => BitConverter.GetBytes(a.S_addr); /// Performs an implicit conversion from to . /// A UInt32 value. /// The result of the conversion. public static implicit operator IN_ADDR(uint a) => new IN_ADDR(a); /// Performs an implicit conversion from to . /// An Int64 value. /// The result of the conversion. public static implicit operator IN_ADDR(long a) => new IN_ADDR((uint)a); /// Returns a that represents this instance. /// A that represents this instance. public override string ToString() { var b = S_un_b; return $"{b[0]}.{b[1]}.{b[2]}.{b[3]}"; } } [PInvokeData("winsock2.h")] [StructLayout(LayoutKind.Sequential, Size = IN6_ADDR_SIZE)] public struct IN6_ADDR : IEquatable { private const int IN6_ADDR_SIZE = 16; private ulong lower; private ulong upper; public static readonly IN6_ADDR Loopback = new IN6_ADDR { lower = 0xff_01_00_00_00_00_00_00, upper = 0x00_00_00_00_00_00_00_01 }; public static readonly IN6_ADDR Unspecified = new IN6_ADDR { lower = 0, upper = 0 }; public IN6_ADDR(byte[] v6addr) { lower = upper = 0; bytes = v6addr; } public unsafe byte[] bytes { get { var v6addr = new byte[IN6_ADDR_SIZE]; fixed (byte* usp = &v6addr[0]) { var ulp2 = (ulong*)usp; ulp2[0] = lower; ulp2[1] = upper; } return v6addr; } set { if (value == null) value = new byte[IN6_ADDR_SIZE]; if (value.Length != IN6_ADDR_SIZE) throw new ArgumentException("Byte array must have 16 items.", nameof(value)); fixed (byte* bp = &value[0]) { var ulp = (ulong*)bp; lower = ulp[0]; upper = ulp[1]; } } } public unsafe ushort[] words { get { var v6addr = new ushort[IN6_ADDR_SIZE / 2]; fixed (ushort* usp = &v6addr[0]) { var ulp2 = (ulong*)usp; ulp2[0] = lower; ulp2[1] = upper; } return v6addr; } set { if (value == null) value = new ushort[IN6_ADDR_SIZE / 2]; if (value.Length != IN6_ADDR_SIZE / 2) throw new ArgumentException("UInt16 array must have 8 items.", nameof(value)); fixed (ushort* bp = &value[0]) { var ulp = (ulong*)bp; lower = ulp[0]; upper = ulp[1]; } } } public static implicit operator IN6_ADDR(byte[] a) => new IN6_ADDR(a); public static implicit operator byte[] (IN6_ADDR a) => a.bytes; public override string ToString() { const string numberFormat = "{0:x4}:{1:x4}:{2:x4}:{3:x4}:{4:x4}:{5:x4}:{6}.{7}.{8}.{9}"; var m_Numbers = words; return string.Format(System.Globalization.CultureInfo.InvariantCulture, numberFormat, m_Numbers[0], m_Numbers[1], m_Numbers[2], m_Numbers[3], m_Numbers[4], m_Numbers[5], ((m_Numbers[6] >> 8) & 0xFF), (m_Numbers[6] & 0xFF), ((m_Numbers[7] >> 8) & 0xFF), (m_Numbers[7] & 0xFF)); } public bool Equals(IN6_ADDR other) => lower == other.lower && upper == other.upper; } [PInvokeData("winsock2.h")] [StructLayout(LayoutKind.Sequential, Pack = 2)] public struct SOCKADDR_IN { public ADDRESS_FAMILY sin_family; public ushort sin_port; public IN_ADDR sin_addr; public ulong sin_zero; public SOCKADDR_IN(IN_ADDR addr, ushort port = 0) { sin_family = ADDRESS_FAMILY.AF_INET; sin_port = port; sin_addr = addr; sin_zero = 0; } public static implicit operator SOCKADDR_IN(IN_ADDR addr) => new SOCKADDR_IN(addr); public override string ToString() => $"{sin_addr}:{sin_port}"; } [PInvokeData("winsock2.h")] [StructLayout(LayoutKind.Sequential, Pack = 2)] public struct SOCKADDR_IN6 { public ADDRESS_FAMILY sin6_family; public ushort sin6_port; public uint sin6_flowinfo; public IN6_ADDR sin6_addr; public uint sin6_scope_id; public SOCKADDR_IN6(byte[] addr, uint scope_id, ushort port = 0) : this(new IN6_ADDR(addr), scope_id, port) { } public SOCKADDR_IN6(IN6_ADDR addr, uint scope_id, ushort port = 0) { sin6_family = ADDRESS_FAMILY.AF_INET6; sin6_port = port; sin6_flowinfo = 0; sin6_addr = addr; sin6_scope_id = scope_id; } public static implicit operator SOCKADDR_IN6(IN6_ADDR addr) => new SOCKADDR_IN6(addr, 0); public override string ToString() => $"{sin6_addr}" + (sin6_scope_id == 0 ? "" : "%" + sin6_scope_id.ToString()) + $":{sin6_port}"; } /// /// /// The SOCKADDR_IN6_PAIR structure contains pointers to a pair of IP addresses that represent a source and destination /// address pair. /// /// /// /// The SOCKADDR_IN6_PAIR structure is defined on Windows Vista and later. /// /// Any IPv4 addresses in the SOCKADDR_IN6_PAIR structure must be represented in the IPv4-mapped IPv6 address format which /// enables an IPv6 only application to communicate with an IPv4 node. For more information on the IPv4-mapped IPv6 address format, /// see Dual-Stack Sockets. /// /// The SOCKADDR_IN6_PAIR structure is used by the CreateSortedAddressPairs function. /// Note that the Ws2ipdef.h header file is automatically included in Ws2tcpip.h header file, and should never be used directly. /// // https://docs.microsoft.com/en-us/windows/desktop/api/ws2ipdef/ns-ws2ipdef-_sockaddr_in6_pair typedef struct _sockaddr_in6_pair { // PSOCKADDR_IN6 SourceAddress; PSOCKADDR_IN6 DestinationAddress; } SOCKADDR_IN6_PAIR, *PSOCKADDR_IN6_PAIR; [PInvokeData("ws2ipdef.h", MSDNShortId = "0265f8e0-8b35-4d9d-bf22-e98e9ff36a17")] [StructLayout(LayoutKind.Sequential)] public struct SOCKADDR_IN6_PAIR { private IntPtr _SourceAddress; private IntPtr _DestinationAddress; /// /// /// A pointer to an IP source address represented as a SOCKADDR_IN6 structure. The address family is in host byte order and the /// IPv6 address, port, flow information, and zone ID are in network byte order. /// /// public SOCKADDR_IN6 SourceAddress => _SourceAddress.ToStructure(); /// /// /// A pointer to an IP source address represented as a SOCKADDR_IN6 structure. The address family is in host byte order and the /// IPv6 address, port, flow information, and zone ID are in network byte order. /// /// public SOCKADDR_IN6 DestinationAddress => _DestinationAddress.ToStructure(); } [PInvokeData("winsock2.h")] [StructLayout(LayoutKind.Explicit)] public struct SOCKADDR_INET : IEquatable, IEquatable, IEquatable { [FieldOffset(0)] public SOCKADDR_IN Ipv4; [FieldOffset(0)] public SOCKADDR_IN6 Ipv6; [FieldOffset(0)] public ADDRESS_FAMILY si_family; public bool Equals(SOCKADDR_INET other) => (si_family == ADDRESS_FAMILY.AF_INET && Ipv4.Equals(other.Ipv4)) || (si_family == ADDRESS_FAMILY.AF_INET6 && Ipv6.Equals(other.Ipv6)); public bool Equals(SOCKADDR_IN other) => si_family == ADDRESS_FAMILY.AF_INET && Ipv4.Equals(other); public bool Equals(SOCKADDR_IN6 other) => si_family == ADDRESS_FAMILY.AF_INET6 && Ipv6.Equals(other); public static implicit operator SOCKADDR_INET(SOCKADDR_IN address) => new SOCKADDR_INET { Ipv4 = address }; public static implicit operator SOCKADDR_INET(SOCKADDR_IN6 address) => new SOCKADDR_INET { Ipv6 = address }; public override string ToString() { var sb = new System.Text.StringBuilder($"{si_family}"); if (si_family == ADDRESS_FAMILY.AF_INET) sb.Append(":").Append(Ipv4); else if (si_family == ADDRESS_FAMILY.AF_INET6) sb.Append(":").Append(Ipv6); return sb.ToString(); } } [PInvokeData("winsock2.h")] [StructLayout(LayoutKind.Sequential)] public struct SOCKET_ADDRESS { public IntPtr lpSockAddr; public int iSockaddrLength; public SOCKADDR_INET GetSOCKADDR() => lpSockAddr.ToStructure(); public override string ToString() => GetSOCKADDR().ToString(); } [PInvokeData("winsock2.h")] public class SOCKADDR : SafeMemoryHandle { public SOCKADDR(uint addr, ushort port = 0) : this(BitConverter.GetBytes(addr), port) { } public SOCKADDR(byte[] addr, ushort port = 0, uint scopeId = 0) : base(addr.Length == 4 ? Marshal.SizeOf(typeof(SOCKADDR_IN)) : Marshal.SizeOf(typeof(SOCKADDR_IN6))) { if (addr.Length == 4) { var in4 = new SOCKADDR_IN(new IN_ADDR(addr), port); Marshal.StructureToPtr(in4, handle, false); } else if (addr.Length == 16) { var in6 = new SOCKADDR_IN6(addr, scopeId, port); Marshal.StructureToPtr(in6, handle, false); } else throw new ArgumentOutOfRangeException(nameof(addr)); } public byte[] sa_data => GetBytes(2, 14); public ushort sa_family => handle.ToStructure(); } } }