#pragma warning disable IDE1006 // Naming Styles

using System;
using System.Net;
using System.Runtime.InteropServices;
using Vanara.Extensions;
using Vanara.InteropServices;

namespace Vanara.PInvoke
{
	/// <summary>Functions, structures and constants from ws2_32.h.</summary>
	public static partial class Ws2_32
	{
		/// <summary>
		/// An opaque data structure object from the service provider associated with socket s. This object stores the current configuration
		/// information of the service provider. The exact format of this data structure is service provider specific.
		/// </summary>
		public const int PVD_CONFIG = 0x3001;

		/// <summary>The socket is listening.</summary>
		[CorrespondingType(typeof(BOOL))]
		public const int SO_ACCEPTCONN = 0x0002;

		/// <summary>The socket is configured for the transmission and receipt of broadcast messages.</summary>
		[CorrespondingType(typeof(BOOL))]
		public const int SO_BROADCAST = 0x0020;

		/// <summary>Returns the local address, local port, remote address, remote port, socket type, and protocol used by a socket.</summary>
		[CorrespondingType(typeof(CSADDR_INFO))]
		public const int SO_BSP_STATE = 0x1009;

		/// <summary>Returns current socket state, either from a previous call to setsockopt or the system default.</summary>
		[CorrespondingType(typeof(BOOL))]
		public const int SO_CONDITIONAL_ACCEPT = 0x3002;

		/// <summary></summary>
		public const int SO_CONNDATA = 0x7000;

		/// <summary></summary>
		public const int SO_CONNDATALEN = 0x7004;

		/// <summary>
		/// Returns the number of seconds a socket has been connected. This socket option is valid for connection oriented protocols only.
		/// </summary>
		[CorrespondingType(typeof(uint))]
		public const int SO_CONNECT_TIME = 0x700C;

		/// <summary></summary>
		public const int SO_CONNOPT = 0x7001;

		/// <summary></summary>
		public const int SO_CONNOPTLEN = 0x7005;

		/// <summary>Debugging is enabled.</summary>
		[CorrespondingType(typeof(BOOL))]
		public const int SO_DEBUG = 0x0001;

		/// <summary></summary>
		public const int SO_DISCDATA = 0x7002;

		/// <summary></summary>
		public const int SO_DISCDATALEN = 0x7006;

		/// <summary></summary>
		public const int SO_DISCOPT = 0x7003;

		/// <summary></summary>
		public const int SO_DISCOPTLEN = 0x7007;

		/// <summary>If TRUE, the SO_LINGER option is disabled.</summary>
		[CorrespondingType(typeof(BOOL))]
		public const int SO_DONTLINGER = (int)(~SO_LINGER);

		/// <summary>
		/// Routing is disabled. Setting this succeeds but is ignored on AF_INET sockets; fails on AF_INET6 sockets with WSAENOPROTOOPT.
		/// This option is not supported on ATM sockets.
		/// </summary>
		[CorrespondingType(typeof(BOOL))]
		public const int SO_DONTROUTE = 0x0010;

		/// <summary>Retrieves error status and clear.</summary>
		[CorrespondingType(typeof(int))]
		public const int SO_ERROR = 0x1007;

		/// <summary>
		/// Prevents any other socket from binding to the same address and port. This option must be set before calling the bind function.
		/// </summary>
		[CorrespondingType(typeof(BOOL))]
		public const int SO_EXCLUSIVEADDRUSE = ((int)(~SO_REUSEADDR));

		/// <summary>Reserved.</summary>
		[CorrespondingType(typeof(GROUP))]
		public const int SO_GROUP_ID = 0x2001;

		/// <summary>Reserved.</summary>
		[CorrespondingType(typeof(int))]
		public const int SO_GROUP_PRIORITY = 0x2002;

		/// <summary>Keep-alives are being sent. Not supported on ATM sockets.</summary>
		[CorrespondingType(typeof(BOOL))]
		public const int SO_KEEPALIVE = 0x0008;

		/// <summary>Returns the current linger options.</summary>
		[CorrespondingType(typeof(LINGER))]
		public const int SO_LINGER = 0x0080;

		/// <summary>
		/// The maximum size of a message for message-oriented socket types (for example, SOCK_DGRAM). Has no meaning for stream oriented sockets.
		/// </summary>
		[CorrespondingType(typeof(uint))]
		public const int SO_MAX_MSG_SIZE = 0x2003;

		/// <summary></summary>
		public const int SO_MAXDG = 0x7009;

		/// <summary></summary>
		public const int SO_MAXPATHDG = 0x700A;

		/// <summary>
		/// OOB data is being received in the normal data stream. (See section Windows Sockets 1.1 Blocking Routines and EINPROGRESS for a
		/// discussion of this topic.)
		/// </summary>
		[CorrespondingType(typeof(BOOL))]
		public const int SO_OOBINLINE = 0x0100;

		/// <summary>A description of the protocol information for the protocol that is bound to this socket.</summary>
		[CorrespondingType(typeof(WSAPROTOCOL_INFO))]
		public const int SO_PROTOCOL_INFO = SO_PROTOCOL_INFOW;

		/// <summary>A description of the protocol information for the protocol that is bound to this socket.</summary>
		[CorrespondingType(typeof(WSAPROTOCOL_INFO))]
		public const int SO_PROTOCOL_INFOA = 0x2004;

		/// <summary>A description of the protocol information for the protocol that is bound to this socket.</summary>
		[CorrespondingType(typeof(WSAPROTOCOL_INFO))]
		public const int SO_PROTOCOL_INFOW = 0x2005;

		/// <summary>
		/// The total per-socket buffer space reserved for receives. This is unrelated to SO_MAX_MSG_SIZE and does not necessarily
		/// correspond to the size of the TCP receive window.
		/// </summary>
		[CorrespondingType(typeof(int))]
		public const int SO_RCVBUF = 0x1002;

		/// <summary>Receives low watermark.</summary>
		[CorrespondingType(typeof(int))]
		public const int SO_RCVLOWAT = 0x1004;

		/// <summary>Receives time-out.</summary>
		[CorrespondingType(typeof(int))]
		public const int SO_RCVTIMEO = 0x1006;

		/// <summary>The socket can be bound to an address which is already in use. Not applicable for ATM sockets.</summary>
		[CorrespondingType(typeof(BOOL))]
		public const int SO_REUSEADDR = 0x0004;

		/// <summary>
		/// The total per-socket buffer space reserved for sends. This is unrelated to SO_MAX_MSG_SIZE and does not necessarily correspond
		/// to the size of a TCP send window.
		/// </summary>
		[CorrespondingType(typeof(int))]
		public const int SO_SNDBUF = 0x1001;

		/// <summary>Sends low watermark.</summary>
		[CorrespondingType(typeof(int))]
		public const int SO_SNDLOWAT = 0x1003;

		/// <summary>Sends time-out.</summary>
		[CorrespondingType(typeof(int))]
		public const int SO_SNDTIMEO = 0x1005;

		/// <summary>The type of the socket (for example, SOCK_STREAM).</summary>
		[CorrespondingType(typeof(int))]
		public const int SO_TYPE = 0x1008;

		/// <summary></summary>
		public const int SO_UPDATE_ACCEPT_CONTEXT = 0x700B;

		/// <summary></summary>
		public const int SO_USELOOPBACK = 0x0040;

		/// <summary>A value that indicates a function failure.</summary>
		public const uint SOCKET_ERROR = unchecked((uint)-1);

		/// <summary>The socket option level.</summary>
		public const int SOL_SOCKET = 0xffff;

		/// <summary>Maximum queue length specifiable by listen.</summary>
		public const int SOMAXCONN = 0x7fffffff;

		/// <summary></summary>
		public const int TCP_BSDURGENT = 0x7000;

		/// <summary>Disables the Nagle algorithm for send coalescing.</summary>
		[CorrespondingType(typeof(BOOL))]
		public const int TCP_NODELAY = 0x0001;

		/// <summary>The application-specified callback function for <see cref="WSAAccept"/>.</summary>
		/// <param name="lpCallerId">
		/// A WSABUF structure that contains the address of the connecting entity, where its len parameter is the length of the buffer in
		/// bytes, and its buf parameter is a pointer to the buffer..
		/// </param>
		/// <param name="lpCallerData">
		/// A value parameter that contains any user data. The information in these parameters is sent along with the connection request. If
		/// no caller identification or caller data is available, the corresponding parameters will be NULL. Many network protocols do not
		/// support connect-time caller data. Most conventional network protocols can be expected to support caller identifier information
		/// at connection-request time. The buf portion of the WSABUF pointed to by lpCallerId points to a sockaddr. The sockaddr structure
		/// is interpreted according to its address family (typically by casting the sockaddr to some type specific to the address family).
		/// </param>
		/// <param name="lpSQOS">
		/// References the FLOWSPEC structures for socket s specified by the caller, one for each direction, followed by any additional
		/// provider-specific parameters. The sending or receiving flow specification values will be ignored as appropriate for any
		/// unidirectional sockets. A NULL value indicates that there is no caller-supplied quality of service and that no negotiation is
		/// possible. A non-NULL lpSQOS pointer indicates that a quality of service negotiation is to occur or that the provider is prepared
		/// to accept the quality of service request without negotiation.
		/// </param>
		/// <param name="lpGQOS">
		/// Reserved, and should be NULL. (reserved for future use with socket groups) references the FLOWSPEC structure for the socket
		/// group the caller is to create, one for each direction, followed by any additional provider-specific parameters. A NULL value for
		/// lpGQOS indicates no caller-specified group quality of service. Quality of service information can be returned if negotiation is
		/// to occur.
		/// </param>
		/// <param name="lpCalleeId">
		/// Contains the local address of the connected entity. The buf portion of the WSABUF pointed to by lpCalleeId points to a sockaddr
		/// structure. The sockaddr structure is interpreted according to its address family (typically by casting the sockaddr to some type
		/// specific to the address family such as struct sockaddr_in).
		/// </param>
		/// <param name="lpCalleeData">
		/// A result parameter used by the condition function to supply user data back to the connecting entity. The lpCalleeData-&gt;len
		/// initially contains the length of the buffer allocated by the service provider and pointed to by lpCalleeData-&gt;buf. A value of
		/// zero means passing user data back to the caller is not supported. The condition function should copy up to lpCalleeData-&gt;len
		/// bytes of data into lpCalleeData-&gt;buf, and then update lpCalleeData-&gt;len to indicate the actual number of bytes
		/// transferred. If no user data is to be passed back to the caller, the condition function should set lpCalleeData-&gt;len to zero.
		/// The format of all address and user data is specific to the address family to which the socket belongs.
		/// </param>
		/// <param name="g">
		/// <para>Assigned within the condition function to indicate any of the following actions:</para>
		/// <list type="bullet">
		/// <item>
		/// If g is an existing socket group identifier, add s to this group, provided all the requirements set by this group are met.
		/// </item>
		/// <item>If g = SG_UNCONSTRAINED_GROUP, create an unconstrained socket group and have s as the first member.</item>
		/// <item>If g = SG_CONSTRAINED_GROUP, create a constrained socket group and have s as the first member.</item>
		/// <item>If g = zero, no group operation is performed.</item>
		/// </list>
		/// <para>
		/// For unconstrained groups, any set of sockets can be grouped together as long as they are supported by a single service provider.
		/// A constrained socket group can consist only of connection-oriented sockets, and requires that connections on all grouped sockets
		/// be to the same address on the same host.For newly created socket groups, the new group identifier can be retrieved by using
		/// getsockopt function with level parameter set to SOL_SOCKET and the optname parameter set to SO_GROUP_ID.A socket group and its
		/// associated socket group ID remain valid until the last socket belonging to this socket group is closed.Socket group IDs are
		/// unique across all processes for a given service provider. A socket group and its associated identifier remain valid until the
		/// last socket belonging to this socket group is closed.Socket group identifiers are unique across all processes for a given
		/// service provider. For more information on socket groups, see the Remarks for the WSASocket functions.
		/// </para>
		/// </param>
		/// <param name="dwCallbackData">
		/// Value passed to the condition function is the value passed as the dwCallbackData parameter in the original WSAAccept call. This
		/// value is interpreted only by the Windows Socket version 2 client. This allows a client to pass some context information from the
		/// WSAAccept call site through to the condition function. This also provides the condition function with any additional information
		/// required to determine whether to accept the connection or not. A typical usage is to pass a (suitably cast) pointer to a data
		/// structure containing references to application-defined objects with which this socket is associated.
		/// </param>
		/// <returns></returns>
		[PInvokeData("winsock2.h", MSDNShortId = "f385f63f-49b2-4eb7-8717-ad4cca1a2252")]
		[UnmanagedFunctionPointer(CallingConvention.Winapi, CharSet = CharSet.Unicode)]
		public delegate CF ConditionFunc(in WSABUF lpCallerId, in WSABUF lpCallerData, IntPtr lpSQOS, IntPtr lpGQOS, in WSABUF lpCalleeId, in WSABUF lpCalleeData, out GROUP g, IntPtr dwCallbackData);

		/// <summary>The address family specification.</summary>
		[PInvokeData("winsock2.h")]
		public enum ADDRESS_FAMILY : ushort
		{
			/// <summary>Unspecified address family.</summary>
			AF_UNSPEC = 0,

			/// <summary>Unix local to host address.</summary>
			AF_UNIX = 1,

			/// <summary>Address for IP version 4.</summary>
			AF_INET = 2,

			/// <summary>ARPANET IMP address.</summary>
			AF_IMPLINK = 3,

			/// <summary>Address for PUP protocols.</summary>
			AF_PUP = 4,

			/// <summary>Address for MIT CHAOS protocols.</summary>
			AF_CHAOS = 5,

			/// <summary>Address for Xerox NS protocols.</summary>
			AF_NS = 6,

			/// <summary>IPX or SPX address.</summary>
			AF_IPX = AF_NS,

			/// <summary>Address for ISO protocols.</summary>
			AF_ISO = 7,

			/// <summary>Address for OSI protocols.</summary>
			AF_OSI = AF_ISO,

			/// <summary>European Computer Manufacturers Association (ECMA) address.</summary>
			AF_ECMA = 8,

			/// <summary>Address for Datakit protocols.</summary>
			AF_DATAKIT = 9,

			/// <summary>Addresses for CCITT protocols, such as X.25.</summary>
			AF_CCITT = 10,

			/// <summary>IBM SNA address.</summary>
			AF_SNA = 11,

			/// <summary>DECnet address.</summary>
			AF_DECnet = 12,

			/// <summary>Direct data-link interface address.</summary>
			AF_DLI = 13,

			/// <summary>LAT address.</summary>
			AF_LAT = 14,

			/// <summary>NSC Hyperchannel address.</summary>
			AF_HYLINK = 15,

			/// <summary>AppleTalk address.</summary>
			AF_APPLETALK = 16,

			/// <summary>NetBios address.</summary>
			AF_NETBIOS = 17,

			/// <summary>VoiceView address.</summary>
			AF_VOICEVIEW = 18,

			/// <summary>FireFox address.</summary>
			AF_FIREFOX = 19,

			/// <summary>Undocumented.</summary>
			AF_UNKNOWN1 = 20,

			/// <summary>Banyan address.</summary>
			AF_BAN = 21,

			/// <summary>Native ATM services address.</summary>
			AF_ATM = 22,

			/// <summary>Address for IP version 6.</summary>
			AF_INET6 = 23,

			/// <summary>Address for Microsoft cluster products.</summary>
			AF_CLUSTER = 24,

			/// <summary>IEEE 1284.4 workgroup address.</summary>
			AF_12844 = 25,

			/// <summary>IrDA address.</summary>
			AF_IRDA = 26,

			/// <summary>Address for Network Designers OSI gateway-enabled protocols.</summary>
			AF_NETDES = 28,

			/// <summary>Undocumented.</summary>
			AF_TCNPROCESS = 29,

			/// <summary>Undocumented.</summary>
			AF_TCNMESSAGE = 30,

			/// <summary>Undocumented.</summary>
			AF_ICLFXBM = 31,

			/// <summary>Bluetooth RFCOMM/L2CAP protocols.</summary>
			AF_BTH = 32,

			/// <summary>Link layer interface.</summary>
			AF_LINK = 33,

			/// <summary>Windows Hyper-V.</summary>
			AF_HYPERV = 34,
		}

		/// <summary>Possible return values to WSAAccept from the LPCONDITIONPROC.</summary>
		[PInvokeData("winsock2.h", MSDNShortId = "f385f63f-49b2-4eb7-8717-ad4cca1a2252")]
		public enum CF
		{
			/// <summary>
			/// WSAAccept creates a new socket. The newly created socket has the same properties as socket s including asynchronous events
			/// registered with WSAAsyncSelect or with WSAEventSelect.
			/// </summary>
			CF_ACCEPT = 0x0000,

			/// <summary>
			/// WSAAccept rejects the connection request. The condition function runs in the same thread as this function does, and should
			/// return as soon as possible.
			/// </summary>
			CF_REJECT = 0x0001,

			/// <summary>
			/// If the decision cannot be made immediately, the condition function should return CF_DEFER to indicate that no decision has
			/// been made, and no action about this connection request should be taken by the service provider. When the application is
			/// ready to take action on the connection request, it will invoke WSAAccept again and return either CF_ACCEPT or CF_REJECT as a
			/// return value from the condition function.
			/// </summary>
			CF_DEFER = 0x0002
		}

		/// <summary>Socket group flags.</summary>
		[PInvokeData("winsock2.h")]
		[Flags]
		public enum GROUP : uint
		{
			/// <summary>
			/// Create an unconstrained socket group and have the new socket be the first member. For an unconstrained group, Winsock does
			/// not constrain all sockets in the socket group to have been created with the same value for the type and protocol parameters.
			/// </summary>
			SG_UNCONSTRAINED_GROUP = 0x01,

			/// <summary>
			/// Create a constrained socket group and have the new socket be the first member. For a contrained socket group, Winsock
			/// constrains all sockets in the socket group to have been created with the same value for the type and protocol parameters. A
			/// constrained socket group may consist only of connection-oriented sockets, and requires that connections on all grouped
			/// sockets be to the same address on the same host.
			/// </summary>
			SG_CONSTRAINED_GROUP = 0x02
		}

		/// <summary>Protocols. The IPv6 defines are specified in RFC 2292.</summary>
		public enum IPPROTO
		{
			/// <summary/>
			IPPROTO_HOPOPTS = 0,

			/// <summary>
			/// The Internet Control Message Protocol (ICMP). This is a possible value when the af parameter is AF_UNSPEC, AF_INET, or
			/// AF_INET6 and the type parameter is SOCK_RAW or unspecified.
			/// <para>This protocol value is supported on Windows XP and later.</para>
			/// </summary>
			IPPROTO_ICMP = 1,

			/// <summary>
			/// The Internet Group Management Protocol (IGMP). This is a possible value when the af parameter is AF_UNSPEC, AF_INET, or
			/// AF_INET6 and the type parameter is SOCK_RAW or unspecified.
			/// <para>This protocol value is supported on Windows XP and later.</para>
			/// </summary>
			IPPROTO_IGMP = 2,

			/// <summary>
			/// The Bluetooth Radio Frequency Communications (Bluetooth RFCOMM) protocol. This is a possible value when the af parameter is
			/// AF_BTH and the type parameter is SOCK_STREAM.
			/// <para>This protocol value is supported on Windows XP with SP2 or later.</para>
			/// </summary>
			IPPROTO_GGP = 3,

			/// <summary/>
			IPPROTO_IPV4 = 4,

			/// <summary/>
			IPPROTO_ST = 5,

			/// <summary>
			/// The Transmission Control Protocol (TCP). This is a possible value when the af parameter is AF_INET or AF_INET6 and the type
			/// parameter is SOCK_STREAM.
			/// </summary>
			IPPROTO_TCP = 6,

			/// <summary/>
			IPPROTO_CBT = 7,

			/// <summary/>
			IPPROTO_EGP = 8,

			/// <summary/>
			IPPROTO_IGP = 9,

			/// <summary/>
			IPPROTO_PUP = 12,

			/// <summary>
			/// The User Datagram Protocol (UDP). This is a possible value when the af parameter is AF_INET or AF_INET6 and the type
			/// parameter is SOCK_DGRAM.
			/// </summary>
			IPPROTO_UDP = 17,

			/// <summary/>
			IPPROTO_IDP = 22,

			/// <summary/>
			IPPROTO_RDP = 27,

			/// <summary/>
			IPPROTO_IPV6 = 41,

			/// <summary/>
			IPPROTO_ROUTING = 43,

			/// <summary/>
			IPPROTO_FRAGMENT = 44,

			/// <summary/>
			IPPROTO_ESP = 50,

			/// <summary/>
			IPPROTO_AH = 51,

			/// <summary>
			/// The Internet Control Message Protocol Version 6 (ICMPv6). This is a possible value when the af parameter is AF_UNSPEC,
			/// AF_INET, or AF_INET6 and the type parameter is SOCK_RAW or unspecified.
			/// <para>This protocol value is supported on Windows XP and later.</para>
			/// </summary>
			IPPROTO_ICMPV6 = 58,

			/// <summary/>
			IPPROTO_NONE = 59,

			/// <summary/>
			IPPROTO_DSTOPTS = 60,

			/// <summary/>
			IPPROTO_ND = 77,

			/// <summary/>
			IPPROTO_ICLFXBM = 78,

			/// <summary/>
			IPPROTO_PIM = 103,

			/// <summary>
			/// The PGM protocol for reliable multicast. This is a possible value when the af parameter is AF_INET and the type parameter is
			/// SOCK_RDM. On the Windows SDK released for Windows Vista and later, this protocol is also called IPPROTO_PGM.
			/// <para>This protocol value is only supported if the Reliable Multicast Protocol is installed.</para>
			/// </summary>
			IPPROTO_PGM = 113,

			/// <summary/>
			IPPROTO_L2TP = 115,

			/// <summary/>
			IPPROTO_SCTP = 132,

			/// <summary/>
			IPPROTO_RAW = 255,

			/// <summary/>
			IPPROTO_MAX = 256,

			/// <summary/>
			IPPROTO_RESERVED_RAW = 257,

			/// <summary/>
			IPPROTO_RESERVED_IPSEC = 258,

			/// <summary/>
			IPPROTO_RESERVED_IPSECOFFLOAD = 259,

			/// <summary/>
			IPPROTO_RESERVED_WNV = 260,

			/// <summary/>
			IPPROTO_RESERVED_MAX = 261
		}

		/// <summary>Indicate either big-endian or little-endian with the values 0 and 1 respectively.</summary>
		[PInvokeData("winsock2.h", MSDNShortId = "be5f3e81-1442-43c7-9e4e-9eb2b2a05132")]
		public enum NetworkByteOrder
		{
			/// <summary>The bigendian</summary>
			BIGENDIAN = 0x0000,

			/// <summary>The littleendian</summary>
			LITTLEENDIAN = 0x0001
		}

		/// <summary>Namespace identifier.</summary>
		[PInvokeData("winsock2.h", MSDNShortId = "cc4ccb2d-ea5a-48bd-a3ae-f70432ab2c39")]
		public enum NS
		{
			/// <summary>All installed and active namespaces.</summary>
			NS_ALL = 0,

			/// <summary/>
			NS_SAP = (1),

			/// <summary/>
			NS_NDS = (2),

			/// <summary/>
			NS_PEER_BROWSE = (3),

			/// <summary/>
			NS_SLP = (5),

			/// <summary/>
			NS_DHCP = (6),

			/// <summary/>
			NS_TCPIP_LOCAL = (10),

			/// <summary/>
			NS_TCPIP_HOSTS = (11),

			/// <summary>The domain name system (DNS) namespace.</summary>
			NS_DNS = 12,

			/// <summary>The NetBIOS over TCP/IP (NETBT) namespace.</summary>
			NS_NETBT = 13,

			/// <summary>The Windows Internet Naming Service (NS_WINS) namespace.</summary>
			NS_WINS = 14,

			/// <summary>
			/// The network location awareness (NLA) namespace.
			/// <para>This namespace identifier is supported on Windows XP and later.</para>
			/// </summary>
			NS_NLA = 15,

			/// <summary>
			/// The Bluetooth namespace.
			/// <para>This namespace identifier is supported on Windows Vista and later.</para>
			/// </summary>
			NS_BTH = 16,

			/// <summary/>
			NS_LOCALNAME = (19),

			/// <summary/>
			NS_NBP = (20),

			/// <summary/>
			NS_MS = (30),

			/// <summary/>
			NS_STDA = (31),

			/// <summary>The Windows NT Directory Services (NS_NTDS) namespace.</summary>
			NS_NTDS = 32,

			/// <summary>
			/// The email namespace.
			/// <para>This namespace identifier is supported on Windows Vista and later.</para>
			/// </summary>
			NS_EMAIL = 37,

			/// <summary>
			/// The peer-to-peer namespace for a specific peer name.
			/// <para>This namespace identifier is supported on Windows Vista and later.</para>
			/// </summary>
			NS_PNRPNAME = 38,

			/// <summary>
			/// The peer-to-peer namespace for a collection of peer names.
			/// <para>This namespace identifier is supported on Windows Vista and later.</para>
			/// </summary>
			NS_PNRPCLOUD = 39,

			/// <summary/>
			NS_X500 = (40),

			/// <summary/>
			NS_NIS = (41),

			/// <summary/>
			NS_NISPLUS = (42),

			/// <summary/>
			NS_WRQ = (50),

			/// <summary/>
			NS_NETDES = (60)
		}

		/// <summary>A set of flags that provides information on how this protocol is represented in the Winsock catalog.</summary>
		[PInvokeData("winsock2.h", MSDNShortId = "be5f3e81-1442-43c7-9e4e-9eb2b2a05132")]
		[Flags]
		public enum PFL : uint
		{
			/// <summary>
			/// Indicates that this is one of two or more entries for a single protocol (from a given provider) which is capable of
			/// implementing multiple behaviors. An example of this is SPX which, on the receiving side, can behave either as a
			/// message-oriented or a stream-oriented protocol.
			/// </summary>
			PFL_MULTIPLE_PROTO_ENTRIES = 0x00000001,

			/// <summary>
			/// Indicates that this is the recommended or most frequently used entry for a protocol that is capable of implementing multiple behaviors.
			/// </summary>
			PFL_RECOMMENDED_PROTO_ENTRY = 0x00000002,

			/// <summary>
			/// Set by a provider to indicate to the Ws2_32.dll that this protocol should not be returned in the result buffer generated by
			/// WSAEnumProtocols. Obviously, a Windows Sockets 2 application should never see an entry with this bit set.
			/// </summary>
			PFL_HIDDEN = 0x00000004,

			/// <summary>Indicates that a value of zero in the protocol parameter of socket or WSASocket matches this protocol entry.</summary>
			PFL_MATCHES_PROTOCOL_ZERO = 0x00000008,

			/// <summary>
			/// Set by a provider to indicate support for network direct access.
			/// <para>This value is supported on Windows 7 and Windows Server 2008 R2.</para>
			/// </summary>
			PFL_NETWORKDIRECT_PROVIDER = 0x00000010,
		}

		/// <summary>The type specification for the new socket.</summary>
		[PInvokeData("winsock2.h", MSDNShortId = "6bf6e6c4-6268-479c-86a6-52e90cf317db")]
		public enum SOCK
		{
			/// <summary>
			/// A socket type that provides sequenced, reliable, two-way, connection-based byte streams with an OOB data transmission
			/// mechanism. This socket type uses the Transmission Control Protocol (TCP) for the Internet address family (AF_INET or AF_INET6).
			/// </summary>
			SOCK_STREAM = 1,

			/// <summary>
			/// A socket type that supports datagrams, which are connectionless, unreliable buffers of a fixed (typically small) maximum
			/// length. This socket type uses the User Datagram Protocol (UDP) for the Internet address family (AF_INET or AF_INET6).
			/// </summary>
			SOCK_DGRAM = 2,

			/// <summary>
			/// A socket type that provides a raw socket that allows an application to manipulate the next upper-layer protocol header. To
			/// manipulate the IPv4 header, the IP_HDRINCL socket option must be set on the socket. To manipulate the IPv6 header, the
			/// IPV6_HDRINCL socket option must be set on the socket.
			/// </summary>
			SOCK_RAW = 3,

			/// <summary>
			/// A socket type that provides a reliable message datagram. An example of this type is the Pragmatic General Multicast (PGM)
			/// multicast protocol implementation in Windows, often referred to as reliable multicast programming.
			/// <para>This type value is only supported if the Reliable Multicast Protocol is installed.</para>
			/// </summary>
			SOCK_RDM = 4,

			/// <summary>A socket type that provides a pseudo-stream packet based on datagrams.</summary>
			SOCK_SEQPACKET = 5,
		}

		/// <summary>
		/// The Windows Sockets <c>WSAECOMPARATOR</c> enumeration type is used for version-comparison semantics in Windows Sockets 2.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/winsock2/ne-winsock2-wsaecomparator typedef enum _WSAEcomparator { COMP_EQUAL,
		// COMP_NOTLESS } WSAECOMPARATOR, *PWSAECOMPARATOR, *LPWSAECOMPARATOR;
		[PInvokeData("winsock2.h", MSDNShortId = "a1de171e-42d7-4d57-b241-1db9989dbd8e")]
		public enum WSAECOMPARATOR
		{
			/// <summary>Used for determining whether version values are equal.</summary>
			COMP_EQUAL,

			/// <summary>Used for determining whether a version value is no less than a specified value.</summary>
			COMP_NOTLESS,
		}

		/// <summary>A value that determines that operation requested.</summary>
		[PInvokeData("winsock2.h")]
		public enum WSAESETSERVICEOP
		{
			/// <summary>
			/// Register the service. For SAP, this means sending out a periodic broadcast. This is an NOP for the DNS namespace. For
			/// persistent data stores, this means updating the address information.
			/// </summary>
			RNRSERVICE_REGISTER = 0,

			/// <summary>
			/// Remove the service from the registry. For SAP, this means stop sending out the periodic broadcast. This is an NOP for the
			/// DNS namespace. For persistent data stores this means deleting address information.
			/// </summary>
			RNRSERVICE_DEREGISTER,

			/// <summary>
			/// Delete the service from dynamic name and persistent spaces. For services represented by multiple CSADDR_INFO structures
			/// (using the SERVICE_MULTIPLE flag), only the specified address will be deleted, and this must match exactly the corresponding
			/// CSADDR_INFO structure that was specified when the service was registered.
			/// </summary>
			RNRSERVICE_DELETE
		}

		/// <summary>A bitmask that describes the services provided by the protocol.</summary>
		[PInvokeData("winsock2.h", MSDNShortId = "be5f3e81-1442-43c7-9e4e-9eb2b2a05132")]
		[Flags]
		public enum XP1
		{
			/// <summary>Provides connectionless (datagram) service. If not set, the protocol supports connection-oriented data transfer.</summary>
			XP1_CONNECTIONLESS = 0x00000001,

			/// <summary>Guarantees that all data sent will reach the intended destination.</summary>
			XP1_GUARANTEED_DELIVERY = 0x00000002,

			/// <summary>
			/// Guarantees that data only arrives in the order in which it was sent and that it is not duplicated. This characteristic does
			/// not necessarily mean that the data is always delivered, but that any data that is delivered is delivered in the order in
			/// which it was sent.
			/// </summary>
			XP1_GUARANTEED_ORDER = 0x00000004,

			/// <summary>Honors message boundaries—as opposed to a stream-oriented protocol where there is no concept of message boundaries.</summary>
			XP1_MESSAGE_ORIENTED = 0x00000008,

			/// <summary>
			/// A message-oriented protocol, but message boundaries are ignored for all receipts. This is convenient when an application
			/// does not desire message framing to be done by the protocol.
			/// </summary>
			XP1_PSEUDO_STREAM = 0x00000010,

			/// <summary>Supports two-phase (graceful) close. If not set, only abortive closes are performed.</summary>
			XP1_GRACEFUL_CLOSE = 0x00000020,

			/// <summary>Supports expedited (urgent) data.</summary>
			XP1_EXPEDITED_DATA = 0x00000040,

			/// <summary>Supports connect data.</summary>
			XP1_CONNECT_DATA = 0x00000080,

			/// <summary>Supports disconnect data.</summary>
			XP1_DISCONNECT_DATA = 0x00000100,

			/// <summary>Supports a broadcast mechanism.</summary>
			XP1_SUPPORT_BROADCAST = 0x00000200,

			/// <summary>Supports a multipoint or multicast mechanism. Control and data plane attributes are indicated below.</summary>
			XP1_SUPPORT_MULTIPOINT = 0x00000400,

			/// <summary>Indicates whether the control plane is rooted (value = 1) or nonrooted (value = 0).</summary>
			XP1_MULTIPOINT_CONTROL_PLANE = 0x00000800,

			/// <summary>Indicates whether the data plane is rooted (value = 1) or nonrooted (value = 0).</summary>
			XP1_MULTIPOINT_DATA_PLANE = 0x00001000,

			/// <summary>Supports quality of service requests.</summary>
			XP1_QOS_SUPPORTED = 0x00002000,

			/// <summary>Bit is reserved.</summary>
			XP1_INTERRUPT = 0x00004000,

			/// <summary>Protocol is unidirectional in the send direction.</summary>
			XP1_UNI_SEND = 0x00008000,

			/// <summary>Protocol is unidirectional in the recv direction.</summary>
			XP1_UNI_RECV = 0x00010000,

			/// <summary>Socket descriptors returned by the provider are operating system Installable File System (IFS) handles.</summary>
			XP1_IFS_HANDLES = 0x00020000,

			/// <summary>The MSG_PARTIAL flag is supported in WSASend and WSASendTo.</summary>
			XP1_PARTIAL_MESSAGE = 0x00040000,

			/// <summary>
			/// The protocol provides support for SAN.
			/// <para>This value is supported on Windows 7 and Windows Server 2008 R2.</para>
			/// </summary>
			XP1_SAN_SUPPORT_SDP = 0x00080000,
		}

		/// <summary/>
		/// <param name="b"/>
		/// <returns/>
		public static int SOMAXCONN_HINT(int b) => -b;

		/// <summary>
		/// The <c>CSADDR_INFO</c> structure contains Windows Sockets address information for a socket, network service, or namespace provider.
		/// </summary>
		/// <remarks>
		/// <para>The GetAddressByName function obtains Windows Sockets address information using <c>CSADDR_INFO</c> structures.</para>
		/// <para>
		/// The getsockopt function called with the SO_BSP_STATE socket option retrieves a <c>CSADDR_INFO</c> structure for the specified socket.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/nspapi/ns-nspapi-csaddr_info typedef struct _CSADDR_INFO { SOCKET_ADDRESS
		// LocalAddr; SOCKET_ADDRESS RemoteAddr; INT iSocketType; INT iProtocol; } CSADDR_INFO, *PCSADDR_INFO, *LPCSADDR_INFO;
		[PInvokeData("nspapi.h", MSDNShortId = "9cad3586-e315-4f6f-9045-7c95502bb768")]
		[StructLayout(LayoutKind.Sequential)]
		public struct CSADDR_INFO
		{
			/// <summary>
			/// <para>Type: <c>SOCKET_ADDRESS</c></para>
			/// <para>The Windows Sockets local address.</para>
			/// <para>In a client application, pass this address to the <c>bind</c> function to obtain access to a network service.</para>
			/// <para>
			/// In a network service, pass this address to the <c>bind</c> function so that the service is bound to the appropriate local address.
			/// </para>
			/// </summary>
			public SOCKET_ADDRESS LocalAddr;

			/// <summary>
			/// <para>Type: <c>SOCKET_ADDRESS</c></para>
			/// <para>Windows Sockets remote address.</para>
			/// <para>There are several uses for this remote address:</para>
			/// <list type="bullet">
			/// <item>
			/// <term>
			/// You can use this remote address to connect to the service through the connect function. This is useful if an application
			/// performs send/receive operations that involve connection-oriented protocols.
			/// </term>
			/// </item>
			/// <item>
			/// <term>
			/// You can use this remote address with the sendto function when you are communicating over a connectionless (datagram)
			/// protocol. If you are using a connectionless protocol, such as UDP, <c>sendto</c> is typically the way you pass data to the
			/// remote system.
			/// </term>
			/// </item>
			/// </list>
			/// </summary>
			public SOCKET_ADDRESS RemoteAddr;

			/// <summary>
			/// <para>Type: <c>INT</c></para>
			/// <para>The type of Windows socket. Possible values for the socket type are defined in the Winsock2.h header file.</para>
			/// <para>The following table lists the possible values supported for Windows Sockets 2:</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>SOCK_STREAM</term>
			/// <term>
			/// A stream socket. This is a protocol that sends data as a stream of bytes, with no message boundaries. This socket type
			/// provides sequenced, reliable, two-way, connection-based byte streams with an OOB data transmission mechanism. This socket
			/// type uses the Transmission Control Protocol (TCP) for the Internet address family (AF_INET or AF_INET6).
			/// </term>
			/// </item>
			/// <item>
			/// <term>SOCK_DGRAM</term>
			/// <term>
			/// A datagram socket. This socket type supports datagrams, which are connectionless, unreliable buffers of a fixed (typically
			/// small) maximum length. This socket type uses the User Datagram Protocol (UDP) for the Internet address family (AF_INET or
			/// AF_INET6). Services use recvfrom function to obtain datagrams. The listen and accept functions do not work with datagrams.
			/// </term>
			/// </item>
			/// <item>
			/// <term>SOCK_RDM</term>
			/// <term>
			/// A reliable message datagram socket. This socket type preserves message boundaries in data. An example of this type is the
			/// Pragmatic General Multicast (PGM) multicast protocol implementation in Windows, often referred to as reliable multicast programming.
			/// </term>
			/// </item>
			/// <item>
			/// <term>SOCK_SEQPACKET</term>
			/// <term>A sequenced packet stream socket. This socket type provides a pseudo-stream packet based on datagrams.</term>
			/// </item>
			/// </list>
			/// </summary>
			public SOCK iSocketType;

			/// <summary>
			/// <para>Type: <c>INT</c></para>
			/// <para>
			/// The protocol used. The possible options for the protocol parameter are specific to the address family and socket type
			/// specified. Possible values are defined in the Winsock2.h and Wsrm.h header files.
			/// </para>
			/// <para>
			/// On the Windows SDK released for Windows Vista and later, the organization of header files has changed and this parameter can
			/// be one of the values from the <c>IPPROTO</c> enumeration type defined in the Ws2def.h header file. Note that the Ws2def.h
			/// header file is automatically included in Winsock2.h, and should never be used directly.
			/// </para>
			/// <para>The table below lists common values for the protocol although many other values are possible.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>protocol</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>IPPROTO_TCP 6</term>
			/// <term>
			/// The Transmission Control Protocol (TCP). This is a possible value when the address family is AF_INET or AF_INET6 and the
			/// iSocketType member is SOCK_STREAM.
			/// </term>
			/// </item>
			/// <item>
			/// <term>IPPROTO_UDP 17</term>
			/// <term>
			/// The User Datagram Protocol (UDP). This is a possible value when the address family is AF_INET or AF_INET6 and the
			/// iSocketType member is SOCK_DGRAM.
			/// </term>
			/// </item>
			/// <item>
			/// <term>IPPROTO_RM 113</term>
			/// <term>
			/// The PGM protocol for reliable multicast. This is a possible value when the address family is AF_INET and the iSocketType
			/// member is SOCK_RDM. On the Windows SDK released for Windows Vista and later, this value is also called IPPROTO_PGM.
			/// </term>
			/// </item>
			/// </list>
			/// </summary>
			public IPPROTO iProtocol;
		}

		/// <summary>The IN_ADDR structure represents an IPv4 address.</summary>
		[PInvokeData("winsock2.h")]
		[StructLayout(LayoutKind.Sequential)]
		public struct IN_ADDR : IEquatable<IN_ADDR>
		{
			/// <summary>An IPv4 address formatted as a u_long.</summary>
			public uint S_addr;

			/// <summary>Initializes a new instance of the <see cref="IN_ADDR"/> struct.</summary>
			/// <param name="v4addr">An IPv4 address.</param>
			public IN_ADDR(uint v4addr) => S_addr = v4addr;

			/// <summary>Initializes a new instance of the <see cref="IN_ADDR"/> struct.</summary>
			/// <param name="v4addr">An IPv4 address</param>
			/// <exception cref="ArgumentException">Byte array must have 4 items. - v4addr</exception>
			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);
			}

			/// <summary>Initializes a new instance of the <see cref="IN_ADDR"/> struct.</summary>
			/// <param name="b1">The first byte.</param>
			/// <param name="b2">The second byte.</param>
			/// <param name="b3">The third byte.</param>
			/// <param name="b4">The fourth byte.</param>
			public IN_ADDR(byte b1, byte b2, byte b3, byte b4) => S_addr = b1 | (uint)b2 << 8 | (uint)b3 << 16 | (uint)b4 << 24;

			/// <summary>Gets the address represented as four bytes.</summary>
			/// <value>An IPv4 address formatted as four u_chars.</value>
			public byte[] S_un_b => BitConverter.GetBytes(S_addr);

			/// <summary/>
			public static readonly IN_ADDR INADDR_ANY = new IN_ADDR(0U);

			/// <summary/>
			public static readonly IN_ADDR INADDR_LOOPBACK = new IN_ADDR(0x7f000001);

			/// <summary/>
			public static readonly IN_ADDR INADDR_BROADCAST = new IN_ADDR(0xffffffff);

			/// <summary/>
			public static readonly IN_ADDR INADDR_NONE = new IN_ADDR(0xffffffff);

			/// <summary>Implements the operator ==.</summary>
			/// <param name="left">The left.</param>
			/// <param name="right">The right.</param>
			/// <returns>The result of the operator.</returns>
			public static bool operator ==(IN_ADDR left, IN_ADDR right) => left.Equals(right);

			/// <summary>Implements the operator !=.</summary>
			/// <param name="left">The left.</param>
			/// <param name="right">The right.</param>
			/// <returns>The result of the operator.</returns>
			public static bool operator !=(IN_ADDR left, IN_ADDR right) => !left.Equals(right);

			/// <summary>Performs an implicit conversion from <see cref="IN_ADDR"/> to <see cref="System.UInt32"/>.</summary>
			/// <param name="a">An IN_ADDR value.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator uint(IN_ADDR a) => a.S_addr;

			/// <summary>Performs an implicit conversion from <see cref="IN_ADDR"/> to <see cref="System.Int64"/>.</summary>
			/// <param name="a">An IN_ADDR value.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator long(IN_ADDR a) => a.S_addr;

			/// <summary>Performs an implicit conversion from <see cref="IN_ADDR"/> to <see cref="T:byte[]"/>.</summary>
			/// <param name="a">An IN_ADDR value.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator byte[](IN_ADDR a) => BitConverter.GetBytes(a.S_addr);

			/// <summary>Performs an implicit conversion from <see cref="System.UInt32"/> to <see cref="IN_ADDR"/>.</summary>
			/// <param name="a">A UInt32 value.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator IN_ADDR(uint a) => new IN_ADDR(a);

			/// <summary>Performs an implicit conversion from <see cref="System.Int64"/> to <see cref="IN_ADDR"/>.</summary>
			/// <param name="a">An Int64 value.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator IN_ADDR(long a) => new IN_ADDR((uint)a);

			/// <summary>Determines equality between this instance and <paramref name="other"/>.</summary>
			/// <param name="other">The other value to compare.</param>
			/// <returns><see langword="true"/> if <paramref name="other"/> is equal to this instance.</returns>
			public bool Equals(IN_ADDR other) => S_addr == other.S_addr;

			/// <summary>Determines whether the specified <see cref="object"/>, is equal to this instance.</summary>
			/// <param name="obj">The <see cref="object"/> to compare with this instance.</param>
			/// <returns><see langword="true"/> if the specified <see cref="object"/> is equal to this instance; otherwise, <see langword="false"/>.</returns>
			public override bool Equals(object obj) => obj is IN_ADDR i ? Equals(i) : base.Equals(obj);

			/// <summary>Returns a hash code for this instance.</summary>
			/// <returns>A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.</returns>
			public override int GetHashCode() => S_addr.GetHashCode();

			/// <summary>Returns a <see cref="System.String"/> that represents this instance.</summary>
			/// <returns>A <see cref="System.String"/> that represents this instance.</returns>
			public override string ToString()
			{
				var b = S_un_b;
				return $"{b[0]}.{b[1]}.{b[2]}.{b[3]}";
			}
		}

		/// <summary>The IN6_ADDR structure represents an IPv6 address.</summary>
		[PInvokeData("winsock2.h")]
		[StructLayout(LayoutKind.Sequential, Size = IN6_ADDR_SIZE)]
		public struct IN6_ADDR : IEquatable<IN6_ADDR>
		{
			private const int IN6_ADDR_SIZE = 16;

			private ulong lower;
			private ulong upper;

			/// <summary>The IPv6 standard loopback address.</summary>
			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 };

			/// <summary>The IPv6 standard unspecified address.</summary>
			public static readonly IN6_ADDR Unspecified = new IN6_ADDR { lower = 0, upper = 0 };

			/// <summary>Initializes a new instance of the <see cref="IN6_ADDR"/> struct.</summary>
			/// <param name="v6addr">The IPv6 address as an array of bytes.</param>
			public IN6_ADDR(byte[] v6addr)
			{
				lower = upper = 0;
				bytes = v6addr;
			}

			/// <summary>Gets or sets the byte array representing the IPv6 address.</summary>
			/// <value>The bytes.</value>
			/// <exception cref="ArgumentException">Byte array must have 16 items. - value</exception>
			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];
					}
				}
			}

			/// <summary>Gets or sets the array of WORD (ushort) values representing the IPv6 address.</summary>
			/// <value>The array of WORD values.</value>
			/// <exception cref="ArgumentException">UInt16 array must have 8 items. - value</exception>
			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];
					}
				}
			}

			/// <summary>Implements the operator ==.</summary>
			/// <param name="left">The left.</param>
			/// <param name="right">The right.</param>
			/// <returns>The result of the operator.</returns>
			public static bool operator ==(IN6_ADDR left, IN6_ADDR right) => left.Equals(right);

			/// <summary>Implements the operator !=.</summary>
			/// <param name="left">The left.</param>
			/// <param name="right">The right.</param>
			/// <returns>The result of the operator.</returns>
			public static bool operator !=(IN6_ADDR left, IN6_ADDR right) => !left.Equals(right);

			/// <summary>Performs an implicit conversion from <see cref="byte"/>[] to <see cref="IN6_ADDR"/>.</summary>
			/// <param name="a">The byte array.</param>
			/// <returns>The resulting <see cref="IN6_ADDR"/> instance from the conversion.</returns>
			public static implicit operator IN6_ADDR(byte[] a) => new IN6_ADDR(a);

			/// <summary>Performs an implicit conversion from <see cref="IN6_ADDR"/> to <see cref="byte"/>[].</summary>
			/// <param name="a">The <see cref="IN6_ADDR"/> instance.</param>
			/// <returns>The resulting <see cref="byte"/>[] instance from the conversion.</returns>
			public static implicit operator byte[](IN6_ADDR a) => a.bytes;

			/// <summary>Determines whether the specified <see cref="object"/>, is equal to this instance.</summary>
			/// <param name="obj">The <see cref="object"/> to compare with this instance.</param>
			/// <returns><see langword="true"/> if the specified <see cref="object"/> is equal to this instance; otherwise, <see langword="false"/>.</returns>
			public override bool Equals(object obj) => obj is IN6_ADDR i ? Equals(i) : base.Equals(obj);

			/// <summary>Returns a hash code for this instance.</summary>
			/// <returns>A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.</returns>
			public override int GetHashCode() => (lower, upper).GetHashCode();

			/// <summary>Converts to string.</summary>
			/// <returns>A <see cref="string"/> that represents this instance.</returns>
			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));
			}

			/// <summary>Determines whether the specified <paramref name="other"/> value is equal to this instance.</summary>
			/// <param name="other">The value to compare with this instance.</param>
			/// <returns><see langword="true"/> if the specified value is equal to this instance; otherwise, <see langword="false"/>.</returns>
			public bool Equals(IN6_ADDR other) => lower == other.lower && upper == other.upper;
		}

		/// <summary>
		/// The <c>linger</c> structure maintains information about a specific socket that specifies how that socket should behave when data
		/// is queued to be sent and the closesocket function is called on the socket.
		/// </summary>
		/// <remarks>
		/// <para>
		/// The <c>l_onoff</c> member of the <c>linger</c> structure determines whether a socket should remain open for a specified amount
		/// of time after a closesocket function call to enable queued data to be sent. Somewhat confusing is that this member can be
		/// modified in two ways:
		/// </para>
		/// <list type="bullet">
		/// <item>
		/// <term>
		/// Call the setsockopt function with the optname parameter set to <c>SO_DONTLINGER</c>. The optval parameter determines how the
		/// <c>l_onoff</c> member is modified.
		/// </term>
		/// </item>
		/// <item>
		/// <term>
		/// Call the setsockopt function with the optname parameter set to <c>SO_LINGER</c>. The optval parameter specifies how both the
		/// <c>l_onoff</c> and <c>l_linger</c> members are modified.
		/// </term>
		/// </item>
		/// </list>
		/// <para>
		/// The <c>l_linger</c> member of the <c>linger</c> structure determines the amount of time, in seconds, a socket should remain
		/// open. This member is only applicable if the <c>l_onoff</c> member of the <c>linger</c> structure is nonzero.
		/// </para>
		/// <para>
		/// To enable a socket to remain open, an application should set the <c>l_onoff</c> member to a nonzero value and set the
		/// <c>l_linger</c> member to the desired time-out in seconds. To disable a socket from remaining open, an application only needs to
		/// set the <c>l_onoff</c> member of the <c>linger</c> structure to zero.
		/// </para>
		/// <para>
		/// If an application calls the setsockopt function with the optname parameter set to <c>SO_DONTLINGER</c> to set the <c>l_onoff</c>
		/// member to a nonzero value, the value for the <c>l_linger</c> member is not specified. In this case, the time-out used is
		/// implementation dependent. If a previous time-out has been established for a socket (by enabling SO_LINGER), this time-out value
		/// should be reinstated by the service provider.
		/// </para>
		/// <para>Note that enabling a nonzero timeout on a nonblocking socket is not recommended.</para>
		/// <para>
		/// The getsockopt function can be called with the optname parameter set to <c>SO_LINGER</c> to retrieve the current value of the
		/// <c>linger</c> structure associated with a socket.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/winsock/ns-winsock-linger typedef struct linger { u_short l_onoff; u_short
		// l_linger; } LINGER, *PLINGER, *LPLINGER;
		[PInvokeData("winsock.h", MSDNShortId = "c1dbabcf-b5cd-4a9d-9bf9-b04c62117d74")]
		[StructLayout(LayoutKind.Sequential)]
		public struct LINGER
		{
			/// <summary>
			/// <para>Type: <c>u_short</c></para>
			/// <para>
			/// Specifies whether a socket should remain open for a specified amount of time after a closesocket function call to enable
			/// queued data to be sent. This member can have one of the following values.
			/// </para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>0</term>
			/// <term>
			/// The socket will not remain open. This is the value set if the setsockopt function is called with the optname parameter set
			/// to SO_DONTLINGER and the optval parameter is zero. This value is also set if the setsockopt function is called with the
			/// optname parameter set to SO_LINGER and the linger structure passed in the optval parameter has the l_onoff member set to 0.
			/// </term>
			/// </item>
			/// <item>
			/// <term>nonzero</term>
			/// <term>
			/// The socket will remain open for a specified amount of time. This value is set if the setsockopt function is called with the
			/// optname parameter set to SO_DONTLINGER and the optval parameter is nonzero. This value is also set if the setsockopt
			/// function is called with the optname parameter set to SO_LINGER and the linger structure passed in the optval parameter has
			/// the l_onoff member set to a nonzero value.
			/// </term>
			/// </item>
			/// </list>
			/// </summary>
			public ushort l_onoff;

			/// <summary>
			/// <para>Type: <c>u_short</c></para>
			/// <para>
			/// The linger time in seconds. This member specifies how long to remain open after a closesocket function call to enable queued
			/// data to be sent. This member is only applicable if the <c>l_onoff</c> member of the <c>linger</c> structure is set to a
			/// nonzero value.
			/// </para>
			/// <para>
			/// This value is set if the setsockopt function is called with the optname parameter set to <c>SO_LINGER</c>. The optval
			/// parameter passed to the <c>setsockopt</c> function must contain a <c>linger</c> structure that is copied to the internal
			/// <c>linger</c> structure maintained for the socket.
			/// </para>
			/// </summary>
			public ushort l_linger;
		}

		/// <summary>
		/// The <c>QOS</c> structure provides the means by which QOS-enabled applications can specify quality of service parameters for sent
		/// and received traffic on a particular flow.
		/// </summary>
		/// <remarks>
		/// Most applications can fulfill their quality of service requirements without using the ProviderSpecific buffer. However, if the
		/// application must provide information not available with standard Windows 2000 QOS parameters, the ProviderSpecific buffer allows
		/// the application to provide additional parameters for RSVP and/or traffic control.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/winsock2/ns-winsock2-_qualityofservice typedef struct _QualityOfService {
		// FLOWSPEC SendingFlowspec; FLOWSPEC ReceivingFlowspec; WSABUF ProviderSpecific; } QOS, *LPQOS;
		[PInvokeData("winsock2.h", MSDNShortId = "859faa13-bd66-46ee-8452-6ff5d53d66c9")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct QOS
		{
			/// <summary>
			/// Specifies QOS parameters for the sending direction of a particular flow. SendingFlowspec is sent in the form of a FLOWSPEC structure.
			/// </summary>
			public FLOWSPEC SendingFlowspec;

			/// <summary>
			/// Specifies QOS parameters for the receiving direction of a particular flow. ReceivingFlowspec is sent in the form of a
			/// FLOWSPEC structure.
			/// </summary>
			public FLOWSPEC ReceivingFlowspec;

			/// <summary>
			/// Pointer to a structure of type WSABUF that can provide additional provider-specific quality of service parameters to the
			/// RSVP SP for a given flow.
			/// </summary>
			public WSABUF ProviderSpecific;
		}

		/// <summary>Provides a handle to a socket.</summary>
		/// <seealso cref="Vanara.PInvoke.IHandle"/>
		[PInvokeData("winsock2.h")]
		[StructLayout(LayoutKind.Sequential)]
		public struct SOCKET : IHandle
		{
			/// <summary>The handle</summary>
			private IntPtr handle;

			/// <summary>Initializes a new instance of the <see cref="SOCKET"/> struct.</summary>
			/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
			public SOCKET(IntPtr preexistingHandle) => handle = preexistingHandle;

			/// <summary>Represents an invalid socket which is different than a null socket.</summary>
			/// <value>The invalid socket.</value>
			public static SOCKET INVALID_SOCKET => new SOCKET(new IntPtr(-1));

			/// <summary>Returns an invalid handle by instantiating a <see cref="SOCKET"/> object with <see cref="IntPtr.Zero"/>.</summary>
			/// <value>Returns a <see cref="SOCKET"/> value.</value>
			public static SOCKET NULL => new SOCKET(IntPtr.Zero);

			/// <summary>Gets a value indicating whether this instance is a null handle.</summary>
			/// <value><see langword="true"/> if this instance is null; otherwise, <see langword="false"/>.</value>
			public bool IsNull => handle == IntPtr.Zero;

			/// <summary>Performs an explicit conversion from <see cref="SOCKET"/> to <see cref="IntPtr"/>.</summary>
			/// <param name="h">The handle.</param>
			/// <returns>The result of the conversion.</returns>
			public static explicit operator IntPtr(SOCKET h) => h.handle;

			/// <summary>Performs an implicit conversion from <see cref="IntPtr"/> to <see cref="SOCKET"/>.</summary>
			/// <param name="h">The pointer to a handle.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator SOCKET(IntPtr h) => new SOCKET(h);

			/// <summary>Implements the operator !=.</summary>
			/// <param name="h1">The first handle.</param>
			/// <param name="h2">The second handle.</param>
			/// <returns>The result of the operator.</returns>
			public static bool operator !=(SOCKET h1, SOCKET h2) => !(h1 == h2);

			/// <summary>Implements the operator ==.</summary>
			/// <param name="h1">The first handle.</param>
			/// <param name="h2">The second handle.</param>
			/// <returns>The result of the operator.</returns>
			public static bool operator ==(SOCKET h1, SOCKET h2) => h1.Equals(h2);

			/// <summary>Determines whether the specified <see cref="System.Object"/>, is equal to this instance.</summary>
			/// <param name="obj">The <see cref="System.Object"/> to compare with this instance.</param>
			/// <returns>
			/// <see langword="true"/> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <see langword="false"/>.
			/// </returns>
			/// <inheritdoc/>
			public override bool Equals(object obj) => obj is SOCKET h ? handle == h.handle : false;

			/// <summary>Returns a hash code for this instance.</summary>
			/// <returns>A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.</returns>
			/// <inheritdoc/>
			public override int GetHashCode() => handle.GetHashCode();

			/// <summary>Returns the value of the handle field.</summary>
			/// <returns>An IntPtr representing the value of the handle field.</returns>
			/// <inheritdoc/>
			public IntPtr DangerousGetHandle() => handle;

			/// <inheritdoc/>
			public override string ToString() => handle.ToString();
		}

		/// <summary>
		/// The <c>timeval</c> structure is used to specify a time interval. It is associated with the Berkeley Software Distribution (BSD)
		/// Time.h header file.
		/// </summary>
		/// <remarks>
		/// <para>
		/// The <c>timeval</c> structure is used in Windows Sockets by the select function to specify the maximum time the function can take
		/// to complete. The time interval is a combination of the values in <c>tv_sec</c> and <c>tv_usec</c> members.
		/// </para>
		/// <para>
		/// Several functions are added on Windows Vista and later that use the <c>timeval</c> structure. These functions include
		/// GetAddrInfoEx, SetAddrInfoEx, WSAConnectByList, and WSAConnectByName.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/winsock/ns-winsock-timeval typedef struct timeval { long tv_sec; long tv_usec;
		// } TIMEVAL, *PTIMEVAL, *LPTIMEVAL;
		[PInvokeData("winsock.h", MSDNShortId = "3024c961-bb47-40ac-a49c-b12cd431e4e7")]
		[StructLayout(LayoutKind.Sequential)]
		public struct TIMEVAL
		{
			/// <summary>Time interval, in seconds.</summary>
			public int tv_sec;

			/// <summary>
			/// Time interval, in microseconds. This value is used in combination with the <c>tv_sec</c> member to represent time interval
			/// values that are not a multiple of seconds.
			/// </summary>
			public int tv_usec;

			/// <summary>Performs an explicit conversion from <see cref="TimeSpan"/> to <see cref="TIMEVAL"/>.</summary>
			/// <param name="timeSpan">The time span.</param>
			/// <returns>The resulting <see cref="TIMEVAL"/> instance from the conversion.</returns>
			public static explicit operator TIMEVAL(TimeSpan timeSpan)
			{
				var tr = Math.Truncate(timeSpan.TotalSeconds);
				return new TIMEVAL { tv_sec = (int)tr, tv_usec = (int)((timeSpan.Ticks - TimeSpan.TicksPerSecond * (long)tr) / TimeSpan.TicksPerMillisecond) };
			}
		}

		/// <summary>The <c>WSADATA</c> structure contains information about the Windows Sockets implementation.</summary>
		/// <remarks>
		/// <para>
		/// The WSAStartup function initiates the use of the Windows Sockets DLL by a process. The <c>WSAStartup</c> function returns a
		/// pointer to the <c>WSADATA</c> structure in the lpWSADataparameter.
		/// </para>
		/// <para>The current version of the Windows Sockets specification returned in the <c>wHighVersion</c> member of the</para>
		/// <para>
		/// <c>WSADATA</c> structure is version 2.2 encoded with the major version number in the low-byte and the minor version number in
		/// the high-byte. This version of the current Winsock DLL, Ws2_32.dll, supports applications that request any of the following
		/// versions of the Windows Sockets specification:
		/// </para>
		/// <list type="bullet">
		/// <item>
		/// <term>1.0</term>
		/// </item>
		/// <item>
		/// <term>1.1</term>
		/// </item>
		/// <item>
		/// <term>2.0</term>
		/// </item>
		/// <item>
		/// <term>2.1</term>
		/// </item>
		/// <item>
		/// <term>2.2</term>
		/// </item>
		/// </list>
		/// <para>
		/// Depending on the version requested by the application, one of the above version numbers is the value encoded as the major
		/// version number in the low-byte and the minor version number in the high-byte that is returned in the <c>wVersion</c> member of
		/// the <c>WSADATA</c> structure.
		/// </para>
		/// <para>
		/// <c>Note</c> An application should ignore the <c>iMaxsockets</c>, <c>iMaxUdpDg</c>, and <c>lpVendorInfo</c> members in
		/// <c>WSADATA</c> if the value in <c>wVersion</c> after a successful call to WSAStartup is at least 2. This is because the
		/// architecture of Windows Sockets changed in version 2 to support multiple providers, and <c>WSADATA</c> no longer applies to a
		/// single vendor's stack. Two new socket options are introduced to supply provider-specific information: SO_MAX_MSG_SIZE (replaces
		/// the <c>iMaxUdpDg</c> member) and PVD_CONFIG (allows any other provider-specific configuration to occur).
		/// </para>
		/// <para>Examples</para>
		/// <para>The following example demonstrates the use of the <c>WSADATA</c> structure.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/winsock/ns-winsock-wsadata typedef struct WSAData { WORD wVersion; WORD
		// wHighVersion; unsigned short iMaxSockets; unsigned short iMaxUdpDg; char *lpVendorInfo; char szDescription[WSADESCRIPTION_LEN +
		// 1]; char szSystemStatus[WSASYS_STATUS_LEN + 1]; } WSADATA;
		[PInvokeData("winsock.h", MSDNShortId = "c3c4c0d6-c8b3-4991-bedb-f45816cc8160")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
		public struct WSADATA
		{
			private const int WSADESCRIPTION_LEN = 256;
			private const int WSASYS_STATUS_LEN = 128;

			/// <summary>
			/// <para>Type: <c>WORD</c></para>
			/// <para>
			/// The version of the Windows Sockets specification that the Ws2_32.dll expects the caller to use. The high-order byte
			/// specifies the minor version number; the low-order byte specifies the major version number.
			/// </para>
			/// </summary>
			public ushort wVersion;

			/// <summary>
			/// <para>Type: <c>WORD</c></para>
			/// <para>
			/// The highest version of the Windows Sockets specification that the Ws2_32.dll can support. The high-order byte specifies the
			/// minor version number; the low-order byte specifies the major version number.
			/// </para>
			/// <para>
			/// This is the same value as the <c>wVersion</c> member when the version requested in the wVersionRequested parameter passed to
			/// the WSAStartup function is the highest version of the Windows Sockets specification that the Ws2_32.dll can support.
			/// </para>
			/// </summary>
			public ushort wHighVersion;

			/// <summary>
			/// <para>Type: <c>unsigned short</c></para>
			/// <para>
			/// The maximum number of sockets that may be opened. This member should be ignored for Windows Sockets version 2 and later.
			/// </para>
			/// <para>
			/// The <c>iMaxSockets</c> member is retained for compatibility with Windows Sockets specification 1.1, but should not be used
			/// when developing new applications. No single value can be appropriate for all underlying service providers. The architecture
			/// of Windows Sockets changed in version 2 to support multiple providers, and the <c>WSADATA</c> structure no longer applies to
			/// a single vendor's stack.
			/// </para>
			/// </summary>
			public ushort iMaxSockets;

			/// <summary>
			/// <para>Type: <c>unsigned short</c></para>
			/// <para>The maximum datagram message size. This member is ignored for Windows Sockets version 2 and later.</para>
			/// <para>
			/// The <c>iMaxUdpDg</c> member is retained for compatibility with Windows Sockets specification 1.1, but should not be used
			/// when developing new applications. The architecture of Windows Sockets changed in version 2 to support multiple providers,
			/// and the <c>WSADATA</c> structure no longer applies to a single vendor's stack. For the actual maximum message size specific
			/// to a particular Windows Sockets service provider and socket type, applications should use getsockopt to retrieve the value
			/// of option SO_MAX_MSG_SIZE after a socket has been created.
			/// </para>
			/// </summary>
			public ushort iMaxUdpDg;

			/// <summary>
			/// <para>Type: <c>char FAR*</c></para>
			/// <para>A pointer to vendor-specific information. This member should be ignored for Windows Sockets version 2 and later.</para>
			/// <para>
			/// The <c>lpVendorInfo</c> member is retained for compatibility with Windows Sockets specification 1.1. The architecture of
			/// Windows Sockets changed in version 2 to support multiple providers, and the <c>WSADATA</c> structure no longer applies to a
			/// single vendor's stack. Applications needing to access vendor-specific configuration information should use getsockopt to
			/// retrieve the value of option PVD_CONFIG for vendor-specific information.
			/// </para>
			/// </summary>
			public IntPtr lpVendorInfo;

			/// <summary>
			/// <para>Type: <c>char[WSADESCRIPTION_LEN+1]</c></para>
			/// <para>
			/// A <c>NULL</c>-terminated ASCII string into which the Ws2_32.dll copies a description of the Windows Sockets implementation.
			/// The text (up to 256 characters in length) can contain any characters except control and formatting characters. The most
			/// likely use that an application would have for this member is to display it (possibly truncated) in a status message.
			/// </para>
			/// </summary>
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = WSADESCRIPTION_LEN + 1)]
			public string szDescription;

			/// <summary>
			/// <para>Type: <c>char[WSASYS_STATUS_LEN+1]</c></para>
			/// <para>
			/// A <c>NULL</c>-terminated ASCII string into which the Ws2_32.dll copies relevant status or configuration information. The
			/// Ws2_32.dll should use this parameter only if the information might be useful to the user or support staff. This member
			/// should not be considered as an extension of the <c>szDescription</c> parameter.
			/// </para>
			/// </summary>
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = WSASYS_STATUS_LEN + 1)]
			public string szSystemStatus;
		}

		/// <summary>
		/// <para>The <c>WSAPROTOCOL_INFO</c> structure is used to store or retrieve complete information for a given protocol.</para>
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/winsock2/ns-winsock2-_wsaprotocol_infoa typedef struct _WSAPROTOCOL_INFOA {
		// DWORD dwServiceFlags1; DWORD dwServiceFlags2; DWORD dwServiceFlags3; DWORD dwServiceFlags4; DWORD dwProviderFlags; GUID
		// ProviderId; DWORD dwCatalogEntryId; WSAPROTOCOLCHAIN ProtocolChain; int iVersion; int iAddressFamily; int iMaxSockAddr; int
		// iMinSockAddr; int iSocketType; int iProtocol; int iProtocolMaxOffset; int iNetworkByteOrder; int iSecurityScheme; DWORD
		// dwMessageSize; DWORD dwProviderReserved; CHAR szProtocol[WSAPROTOCOL_LEN + 1]; } WSAPROTOCOL_INFOA, *LPWSAPROTOCOL_INFOA;
		[PInvokeData("winsock2.h", MSDNShortId = "758c5553-056f-4ea5-a851-30ef641ffb14")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct WSAPROTOCOL_INFO
		{
			private const int WSAPROTOCOL_LEN = 255;

			/// <summary>
			/// <para>Type: <c>DWORD</c></para>
			/// <para>
			/// A bitmask that describes the services provided by the protocol. The possible values for this member are defined in the
			/// Winsock2.h header file.
			/// </para>
			/// <para>The following values are possible.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>XP1_CONNECTIONLESS 0x00000001</term>
			/// <term>Provides connectionless (datagram) service. If not set, the protocol supports connection-oriented data transfer.</term>
			/// </item>
			/// <item>
			/// <term>XP1_GUARANTEED_DELIVERY 0x00000002</term>
			/// <term>Guarantees that all data sent will reach the intended destination.</term>
			/// </item>
			/// <item>
			/// <term>XP1_GUARANTEED_ORDER 0x00000004</term>
			/// <term>
			/// Guarantees that data only arrives in the order in which it was sent and that it is not duplicated. This characteristic does
			/// not necessarily mean that the data is always delivered, but that any data that is delivered is delivered in the order in
			/// which it was sent.
			/// </term>
			/// </item>
			/// <item>
			/// <term>XP1_MESSAGE_ORIENTED 0x00000008</term>
			/// <term>Honors message boundaries—as opposed to a stream-oriented protocol where there is no concept of message boundaries.</term>
			/// </item>
			/// <item>
			/// <term>XP1_PSEUDO_STREAM 0x00000010</term>
			/// <term>
			/// A message-oriented protocol, but message boundaries are ignored for all receipts. This is convenient when an application
			/// does not desire message framing to be done by the protocol.
			/// </term>
			/// </item>
			/// <item>
			/// <term>XP1_GRACEFUL_CLOSE 0x00000020</term>
			/// <term>Supports two-phase (graceful) close. If not set, only abortive closes are performed.</term>
			/// </item>
			/// <item>
			/// <term>XP1_EXPEDITED_DATA 0x00000040</term>
			/// <term>Supports expedited (urgent) data.</term>
			/// </item>
			/// <item>
			/// <term>XP1_CONNECT_DATA 0x00000080</term>
			/// <term>Supports connect data.</term>
			/// </item>
			/// <item>
			/// <term>XP1_DISCONNECT_DATA 0x00000100</term>
			/// <term>Supports disconnect data.</term>
			/// </item>
			/// <item>
			/// <term>XP1_SUPPORT_BROADCAST 0x00000200</term>
			/// <term>Supports a broadcast mechanism.</term>
			/// </item>
			/// <item>
			/// <term>XP1_SUPPORT_MULTIPOINT 0x00000400</term>
			/// <term>Supports a multipoint or multicast mechanism. Control and data plane attributes are indicated below.</term>
			/// </item>
			/// <item>
			/// <term>XP1_MULTIPOINT_CONTROL_PLANE 0x00000800</term>
			/// <term>Indicates whether the control plane is rooted (value = 1) or nonrooted (value = 0).</term>
			/// </item>
			/// <item>
			/// <term>XP1_MULTIPOINT_DATA_PLANE 0x00001000</term>
			/// <term>Indicates whether the data plane is rooted (value = 1) or nonrooted (value = 0).</term>
			/// </item>
			/// <item>
			/// <term>XP1_QOS_SUPPORTED 0x00002000</term>
			/// <term>Supports quality of service requests.</term>
			/// </item>
			/// <item>
			/// <term>XP1_INTERRUPT</term>
			/// <term>Bit is reserved.</term>
			/// </item>
			/// <item>
			/// <term>XP1_UNI_SEND 0x00008000</term>
			/// <term>Protocol is unidirectional in the send direction.</term>
			/// </item>
			/// <item>
			/// <term>XP1_UNI_RECV 0x00010000</term>
			/// <term>Protocol is unidirectional in the recv direction.</term>
			/// </item>
			/// <item>
			/// <term>XP1_IFS_HANDLES 0x00020000</term>
			/// <term>Socket descriptors returned by the provider are operating system Installable File System (IFS) handles.</term>
			/// </item>
			/// <item>
			/// <term>XP1_PARTIAL_MESSAGE 0x00040000</term>
			/// <term>The MSG_PARTIAL flag is supported in WSASend and WSASendTo.</term>
			/// </item>
			/// <item>
			/// <term>XP1_SAN_SUPPORT_SDP 0x00080000</term>
			/// <term>The protocol provides support for SAN. This value is supported on Windows 7 and Windows Server 2008 R2.</term>
			/// </item>
			/// </list>
			/// <para>
			/// <c>Note</c> Only one of XP1_UNI_SEND or XP1_UNI_RECV values may be set. If a protocol can be unidirectional in either
			/// direction, two WSAPROTOCOL_INFOW structures should be used. When neither bit is set, the protocol is considered to be bidirectional.
			/// </para>
			/// </summary>
			public XP1 dwServiceFlags1;

			/// <summary>
			/// <para>Type: <c>DWORD</c></para>
			/// <para>Reserved for additional protocol-attribute definitions.</para>
			/// </summary>
			public uint dwServiceFlags2;

			/// <summary>
			/// <para>Type: <c>DWORD</c></para>
			/// <para>Reserved for additional protocol-attribute definitions.</para>
			/// </summary>
			public uint dwServiceFlags3;

			/// <summary>
			/// <para>Type: <c>DWORD</c></para>
			/// <para>
			/// A set of flags that provides information on how this protocol is represented in the Winsock catalog. The possible values for
			/// this member are defined in the Winsock2.h header file.
			/// </para>
			/// <para>The following flag values are possible.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>PFL_MULTIPLE_PROTO_ENTRIES 0x00000001</term>
			/// <term>
			/// Indicates that this is one of two or more entries for a single protocol (from a given provider) which is capable of
			/// implementing multiple behaviors. An example of this is SPX which, on the receiving side, can behave either as a
			/// message-oriented or a stream-oriented protocol.
			/// </term>
			/// </item>
			/// <item>
			/// <term>PFL_RECOMMENDED_PROTO_ENTRY 0x00000002</term>
			/// <term>
			/// Indicates that this is the recommended or most frequently used entry for a protocol that is capable of implementing multiple behaviors.
			/// </term>
			/// </item>
			/// <item>
			/// <term>PFL_HIDDEN 0x00000004</term>
			/// <term>
			/// Set by a provider to indicate to the Ws2_32.dll that this protocol should not be returned in the result buffer generated by
			/// WSAEnumProtocols. Obviously, a Windows Sockets 2 application should never see an entry with this bit set.
			/// </term>
			/// </item>
			/// <item>
			/// <term>PFL_MATCHES_PROTOCOL_ZERO 0x00000008</term>
			/// <term>Indicates that a value of zero in the protocol parameter of socket or WSASocket matches this protocol entry.</term>
			/// </item>
			/// <item>
			/// <term>PFL_NETWORKDIRECT_PROVIDER 0x00000010</term>
			/// <term>
			/// Set by a provider to indicate support for network direct access. This value is supported on Windows 7 and Windows Server
			/// 2008 R2.
			/// </term>
			/// </item>
			/// </list>
			/// </summary>
			public uint dwServiceFlags4;

			/// <summary>
			/// <para>Type: <c>DWORD</c></para>
			/// <para>Reserved for additional protocol-attribute definitions.</para>
			/// </summary>
			public uint dwProviderFlags;

			/// <summary>
			/// <para>Type: <c>GUID</c></para>
			/// <para>
			/// A globally unique identifier (GUID) assigned to the provider by the service provider vendor. This value is useful for
			/// instances where more than one service provider is able to implement a particular protocol. An application can use the
			/// <c>ProviderId</c> member to distinguish between providers that might otherwise be indistinguishable.
			/// </para>
			/// </summary>
			public Guid ProviderId;

			/// <summary>
			/// <para>Type: <c>DWORD</c></para>
			/// <para>A unique identifier assigned by the WS2_32.DLL for each <c>WSAPROTOCOL_INFO</c> structure.</para>
			/// </summary>
			public uint dwCatalogEntryId;

			/// <summary>
			/// <para>Type: <c>WSAPROTOCOLCHAIN</c></para>
			/// <para>
			/// The WSAPROTOCOLCHAIN structure associated with the protocol. If the length of the chain is 0, this <c>WSAPROTOCOL_INFO</c>
			/// entry represents a layered protocol which has Windows Sockets 2 SPI as both its top and bottom edges. If the length of the
			/// chain equals 1, this entry represents a base protocol whose Catalog Entry identifier is in the <c>dwCatalogEntryId</c>
			/// member of the <c>WSAPROTOCOL_INFO</c> structure. If the length of the chain is larger than 1, this entry represents a
			/// protocol chain which consists of one or more layered protocols on top of a base protocol. The corresponding Catalog Entry
			/// identifiers are in the ProtocolChain.ChainEntries array starting with the layered protocol at the top (the zero element in
			/// the ProtocolChain.ChainEntries array) and ending with the base protocol. Refer to the Windows Sockets 2 Service Provider
			/// Interface specification for more information on protocol chains.
			/// </para>
			/// </summary>
			public WSAPROTOCOLCHAIN ProtocolChain;

			/// <summary>
			/// <para>Type: <c>int</c></para>
			/// <para>The protocol version identifier.</para>
			/// </summary>
			public int iVersion;

			/// <summary>
			/// <para>Type: <c>int</c></para>
			/// <para>
			/// A value to pass as the address family parameter to the socket or WSASocket function in order to open a socket for this
			/// protocol. This value also uniquely defines the structure of a protocol address for a sockaddr used by the protocol.
			/// </para>
			/// <para>
			/// On the Windows SDK released for Windows Vista and later, the possible values for the address family are defined in the
			/// Ws2def.h header file. Note that the Ws2def.h header file is automatically included in Winsock2.h, and should never be used directly.
			/// </para>
			/// <para>
			/// On versions of the Platform SDK for Windows Server 2003 and older, the possible values for the address family are defined in
			/// the Winsock2.h header file.
			/// </para>
			/// <para>
			/// The values currently supported are AF_INET or AF_INET6, which are the Internet address family formats for IPv4 and IPv6.
			/// Other options for address family (AF_NETBIOS for use with NetBIOS, for example) are supported if a Windows Sockets service
			/// provider for the address family is installed. Note that the values for the AF_ address family and PF_ protocol family
			/// constants are identical (for example, <c>AF_INET</c> and <c>PF_INET</c>), so either constant can be used.
			/// </para>
			/// <para>The table below lists common values for address family although many other values are possible.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>iAddressFamily</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>AF_INET 2</term>
			/// <term>The Internet Protocol version 4 (IPv4) address family.</term>
			/// </item>
			/// <item>
			/// <term>AF_IPX 6</term>
			/// <term>
			/// The IPX/SPX address family. This address family is only supported if the NWLink IPX/SPX NetBIOS Compatible Transport
			/// protocol is installed. This address family is not supported on Windows Vista and later.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AF_APPLETALK 16</term>
			/// <term>
			/// The AppleTalk address family. This address family is only supported if the AppleTalk protocol is installed. This address
			/// family is not supported on Windows Vista and later.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AF_NETBIOS 17</term>
			/// <term>
			/// The NetBIOS address family. This address family is only supported if the Windows Sockets provider for NetBIOS is installed.
			/// The Windows Sockets provider for NetBIOS is supported on 32-bit versions of Windows. This provider is installed by default
			/// on 32-bit versions of Windows. The Windows Sockets provider for NetBIOS is not supported on 64-bit versions of windows
			/// including Windows 7, Windows Server 2008, Windows Vista, Windows Server 2003, or Windows XP. The Windows Sockets provider
			/// for NetBIOS only supports sockets where the type parameter is set to SOCK_DGRAM. The Windows Sockets provider for NetBIOS is
			/// not directly related to the NetBIOS programming interface. The NetBIOS programming interface is not supported on Windows
			/// Vista, Windows Server 2008, and later.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AF_INET6 23</term>
			/// <term>The Internet Protocol version 6 (IPv6) address family.</term>
			/// </item>
			/// <item>
			/// <term>AF_IRDA 26</term>
			/// <term>
			/// The Infrared Data Association (IrDA) address family. This address family is only supported if the computer has an infrared
			/// port and driver installed.
			/// </term>
			/// </item>
			/// <item>
			/// <term>AF_BTH 32</term>
			/// <term>
			/// The Bluetooth address family. This address family is supported on Windows XP with SP2 or later if the computer has a
			/// Bluetooth adapter and driver installed.
			/// </term>
			/// </item>
			/// </list>
			/// </summary>
			public int iAddressFamily;

			/// <summary>
			/// <para>Type: <c>int</c></para>
			/// <para>The maximum address length, in bytes.</para>
			/// </summary>
			public int iMaxSockAddr;

			/// <summary>
			/// <para>Type: <c>int</c></para>
			/// <para>The minimum address length, in bytes.</para>
			/// </summary>
			public int iMinSockAddr;

			/// <summary>
			/// <para>Type: <c>int</c></para>
			/// <para>
			/// A value to pass as the socket type parameter to the socket or WSASocket function in order to open a socket for this
			/// protocol. Possible values for the socket type are defined in the Winsock2.h header file.
			/// </para>
			/// <para>The following table lists the possible values for the <c>iSocketType</c> member supported for Windows Sockets 2:</para>
			/// <list type="table">
			/// <listheader>
			/// <term>iSocketType</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>SOCK_STREAM 1</term>
			/// <term>
			/// A socket type that provides sequenced, reliable, two-way, connection-based byte streams with an OOB data transmission
			/// mechanism. This socket type uses the Transmission Control Protocol (TCP) for the Internet address family (AF_INET or AF_INET6).
			/// </term>
			/// </item>
			/// <item>
			/// <term>SOCK_DGRAM 2</term>
			/// <term>
			/// A socket type that supports datagrams, which are connectionless, unreliable buffers of a fixed (typically small) maximum
			/// length. This socket type uses the User Datagram Protocol (UDP) for the Internet address family (AF_INET or AF_INET6).
			/// </term>
			/// </item>
			/// <item>
			/// <term>SOCK_RAW 3</term>
			/// <term>
			/// A socket type that provides a raw socket that allows an application to manipulate the next upper-layer protocol header. To
			/// manipulate the IPv4 header, the IP_HDRINCL socket option must be set on the socket. To manipulate the IPv6 header, the
			/// IPV6_HDRINCL socket option must be set on the socket.
			/// </term>
			/// </item>
			/// <item>
			/// <term>SOCK_RDM 4</term>
			/// <term>
			/// A socket type that provides a reliable message datagram. An example of this type is the Pragmatic General Multicast (PGM)
			/// multicast protocol implementation in Windows, often referred to as reliable multicast programming. This value is only
			/// supported if the Reliable Multicast Protocol is installed.
			/// </term>
			/// </item>
			/// <item>
			/// <term>SOCK_SEQPACKET 5</term>
			/// <term>A socket type that provides a pseudo-stream packet based on datagrams.</term>
			/// </item>
			/// </list>
			/// </summary>
			public SOCK iSocketType;

			/// <summary>
			/// <para>Type: <c>int</c></para>
			/// <para>
			/// A value to pass as the protocol parameter to the socket or WSASocket function in order to open a socket for this protocol.
			/// The possible options for the <c>iProtocol</c> member are specific to the address family and socket type specified.
			/// </para>
			/// <para>
			/// On the Windows SDK released for Windows Vista and later, this member can be one of the values from the <c>IPPROTO</c>
			/// enumeration type defined in the Ws2def.h header file. Note that the Ws2def.h header file is automatically included in
			/// Winsock2.h, and should never be used directly.
			/// </para>
			/// <para>
			/// On versions of the Platform SDK for Windows Server 2003 and earlier, the possible values for the <c>iProtocol</c> member are
			/// defined in the Winsock2.h and Wsrm.h header files.
			/// </para>
			/// <para>The table below lists common values for the <c>iProtocol</c> although many other values are possible.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>iProtocol</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>IPPROTO_ICMP 1</term>
			/// <term>The Internet Control Message Protocol (ICMP). This value is supported on Windows XP and later.</term>
			/// </item>
			/// <item>
			/// <term>IPPROTO_IGMP 2</term>
			/// <term>The Internet Group Management Protocol (IGMP). This value is supported on Windows XP and later.</term>
			/// </item>
			/// <item>
			/// <term>BTHPROTO_RFCOMM 3</term>
			/// <term>
			/// The Bluetooth Radio Frequency Communications (Bluetooth RFCOMM) protocol. This value is supported on Windows XP with SP2 or later.
			/// </term>
			/// </item>
			/// <item>
			/// <term>IPPROTO_TCP 6</term>
			/// <term>The Transmission Control Protocol (TCP).</term>
			/// </item>
			/// <item>
			/// <term>IPPROTO_UDP 17</term>
			/// <term>The User Datagram Protocol (UDP).</term>
			/// </item>
			/// <item>
			/// <term>IPPROTO_ICMPV6 58</term>
			/// <term>The Internet Control Message Protocol Version 6 (ICMPv6). This value is supported on Windows XP and later.</term>
			/// </item>
			/// <item>
			/// <term>IPPROTO_RM 113</term>
			/// <term>
			/// The PGM protocol for reliable multicast. On the Windows SDK released for Windows Vista and later, this protocol is also
			/// called IPPROTO_PGM. This value is only supported if the Reliable Multicast Protocol is installed.
			/// </term>
			/// </item>
			/// </list>
			/// </summary>
			public IPPROTO iProtocol;

			/// <summary>
			/// <para>Type: <c>int</c></para>
			/// <para>
			/// The maximum value that may be added to <c>iProtocol</c> when supplying a value for the protocol parameter to socket or
			/// WSASocket function. Not all protocols allow a range of values. When this is the case <c>iProtocolMaxOffset</c> is zero.
			/// </para>
			/// </summary>
			public int iProtocolMaxOffset;

			/// <summary>
			/// <para>Type: <c>int</c></para>
			/// <para>
			/// Currently these values are manifest constants (BIGENDIAN and LITTLEENDIAN) that indicate either big-endian or little-endian
			/// with the values 0 and 1 respectively.
			/// </para>
			/// </summary>
			public int iNetworkByteOrder;

			/// <summary>
			/// <para>Type: <c>int</c></para>
			/// <para>
			/// The type of security scheme employed (if any). A value of SECURITY_PROTOCOL_NONE (0) is used for protocols that do not
			/// incorporate security provisions.
			/// </para>
			/// </summary>
			public int iSecurityScheme;

			/// <summary>
			/// <para>Type: <c>DWORD</c></para>
			/// <para>
			/// The maximum message size, in bytes, supported by the protocol. This is the maximum size that can be sent from any of the
			/// host's local interfaces. For protocols that do not support message framing, the actual maximum that can be sent to a given
			/// address may be less. There is no standard provision to determine the maximum inbound message size. The following special
			/// values are defined.
			/// </para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>0</term>
			/// <term>The protocol is stream-oriented and hence the concept of message size is not relevant.</term>
			/// </item>
			/// <item>
			/// <term>0x1</term>
			/// <term>
			/// The maximum outbound (send) message size is dependent on the underlying network MTU (maximum sized transmission unit) and
			/// hence cannot be known until after a socket is bound. Applications should use getsockopt to retrieve the value of
			/// SO_MAX_MSG_SIZE after the socket has been bound to a local address.
			/// </term>
			/// </item>
			/// <item>
			/// <term>0xFFFFFFFF</term>
			/// <term>The protocol is message-oriented, but there is no maximum limit to the size of messages that may be transmitted.</term>
			/// </item>
			/// </list>
			/// </summary>
			public uint dwMessageSize;

			/// <summary>
			/// <para>Type: <c>DWORD</c></para>
			/// <para>Reserved for use by service providers.</para>
			/// </summary>
			public uint dwProviderReserved;

			/// <summary>
			/// <para>Type: <c>TCHAR[WSAPROTOCOL_LEN+1]</c></para>
			/// <para>
			/// An array of characters that contains a human-readable name identifying the protocol, for example "MSAFD Tcpip [UDP/IP]". The
			/// maximum number of characters allowed is WSAPROTOCOL_LEN, which is defined to be 255.
			/// </para>
			/// </summary>
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = WSAPROTOCOL_LEN + 1)]
			public string szProtocol;
		}

		/// <summary>
		/// <para>The <c>WSAPROTOCOLCHAIN</c> structure contains a counted list of Catalog Entry identifiers that comprise a protocol chain.</para>
		/// </summary>
		/// <remarks>
		/// <para>
		/// If the length of the chain is larger than 1, this structure represents a protocol chain which consists of one or more layered
		/// protocols on top of a base protocol. The corresponding Catalog Entry IDs are in the ProtocolChain.ChainEntries array starting
		/// with the layered protocol at the top (the zeroth element in the ProtocolChain.ChainEntries array) and ending with the base
		/// protocol. Refer to Windows Sockets 2 Service Provider Interface for more information on protocol chains.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/winsock2/ns-winsock2-wsaprotocolchain typedef struct _WSAPROTOCOLCHAIN { int
		// ChainLen; DWORD ChainEntries[MAX_PROTOCOL_CHAIN]; } WSAPROTOCOLCHAIN, *LPWSAPROTOCOLCHAIN;
		[PInvokeData("winsock2.h", MSDNShortId = "c0676f45-e3e3-45f2-9b34-d7318fddc282")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct WSAPROTOCOLCHAIN
		{
			private const int MAX_PROTOCOL_CHAIN = 7;

			/// <summary>
			/// <para>Length of the chain, in bytes. The following settings apply:</para>
			/// <para>Setting <c>ChainLen</c> to zero indicates a layered protocol</para>
			/// <para>Setting <c>ChainLen</c> to one indicates a base protocol</para>
			/// <para>Setting <c>ChainLen</c> to greater than one indicates a protocol chain</para>
			/// </summary>
			public int ChainLen;

			/// <summary>
			/// <para>Array of protocol chain entries.</para>
			/// </summary>
			[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_PROTOCOL_CHAIN)]
			public uint[] ChainEntries;
		}

		/// <summary>Provides a <see cref="SafeHandle"/> for <see cref="SOCKET"/> that is disposed using <see cref="closesocket"/>.</summary>
		public class SafeSOCKET : SafeHANDLE
		{
			/// <summary>Initializes a new instance of the <see cref="SafeSOCKET"/> class and assigns an existing handle.</summary>
			/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
			/// <param name="ownsHandle">
			/// <see langword="true"/> to reliably release the handle during the finalization phase; otherwise, <see langword="false"/> (not recommended).
			/// </param>
			public SafeSOCKET(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }

			/// <summary>Initializes a new instance of the <see cref="SafeSOCKET"/> class.</summary>
			private SafeSOCKET() : base() { }

			/// <summary>Represents an invalid socket which is different than a null socket.</summary>
			/// <value>The invalid socket.</value>
			public static SafeSOCKET INVALID_SOCKET => new SafeSOCKET(new IntPtr(-1), false);

			/// <summary>Returns an invalid handle by instantiating a <see cref="SafeSOCKET"/> object with <see cref="IntPtr.Zero"/>.</summary>
			/// <value>Returns a <see cref="SafeSOCKET"/> value.</value>
			public static SafeSOCKET NULL => new SafeSOCKET(IntPtr.Zero, false);

			/// <summary>Performs an implicit conversion from <see cref="SafeSOCKET"/> to <see cref="SOCKET"/>.</summary>
			/// <param name="h">The safe handle instance.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator SOCKET(SafeSOCKET h) => h.handle;

			/// <inheritdoc/>
			protected override bool InternalReleaseHandle() => closesocket(this) == 0;
		}

		/// <summary>
		/// <para>
		/// The sockaddr structure varies depending on the protocol selected. Except for the sin*_family parameter, sockaddr contents are
		/// expressed in network byte order.
		/// </para>
		/// <para>
		/// Winsock functions using sockaddr are not strictly interpreted to be pointers to a sockaddr structure. The structure is
		/// interpreted differently in the context of different address families. The only requirements are that the first <c>u_short</c> is
		/// the address family and the total size of the memory buffer in bytes is namelen.
		/// </para>
		/// <para>
		/// The <c>SOCKADDR_STORAGE</c> structure also stores socket address information and the structure is sufficiently large to store
		/// IPv4 or IPv6 address information. The use of the <c>SOCKADDR_STORAGE</c> structure promotes protocol-family and protocol-version
		/// independence, and simplifies development. It is recommended that the <c>SOCKADDR_STORAGE</c> structure be used in place of the
		/// sockaddr structure. The <c>SOCKADDR_STORAGE</c> structure is supported on Windows Server 2003 and later.
		/// </para>
		/// <para>The sockaddr structure and sockaddr_in structures below are used with IPv4. Other protocols use similar structures.</para>
		/// <para>The sockaddr_in6 and sockaddr_in6_old structures below are used with IPv6.</para>
		/// <para>
		/// On the Microsoft Windows Software Development Kit (SDK) released for Windows Vista and later, <c>SOCKADDR</c> and
		/// <c>SOCKADDR_IN</c> typedef tags are defined for sockaddr and sockaddr_in structures as follows:
		/// </para>
		/// <para>
		/// On the Windows SDK released for Windows Vista and later, the organization of header files has changed and the sockaddr and
		/// sockaddr_in structures are defined in the Ws2def.h header file, not the Winsock2.h header file. The Ws2def.h header file is
		/// automatically included by the Winsock2.h header file. The sockaddr_in6 structure is defined in the Ws2ipdef.h header file, not
		/// the Ws2tcpip.h header file. The Ws2ipdef.h header file is automatically included by the Ws2tcpip.h header file. The Ws2def.h and
		/// Ws2ipdef.h header files should never be used directly.
		/// </para>
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/win32/winsock/sockaddr-2
		[PInvokeData("winsock2.h", MSDNShortId = "d1392e1c-2b20-425a-8adf-38e665fb6275")]
		public class SOCKADDR : SafeMemoryHandle<CoTaskMemoryMethods>
		{
			/// <summary>Initializes a new instance of the <see cref="SOCKADDR"/> class.</summary>
			/// <param name="handle">The handle to the memory with the address.</param>
			/// <param name="ownsHandle">if set to <see langword="true"/> this class with dispose the memory.</param>
			/// <param name="size">The size of the memory pointed to by <paramref name="handle"/>.</param>
			public SOCKADDR(IntPtr handle, bool ownsHandle = false, int size = 0) : base(handle, size, ownsHandle) { }

			/// <summary>Initializes a new instance of the <see cref="SOCKADDR"/> class.</summary>
			/// <param name="addr">The IPv4 address value.</param>
			/// <param name="port">The port.</param>
			public SOCKADDR(uint addr, ushort port = 0) : this(BitConverter.GetBytes(addr), port)
			{
			}

			/// <summary>Initializes a new instance of the <see cref="SOCKADDR"/> class.</summary>
			/// <param name="addr">The IPv4 or IPv6 address as a byte array.</param>
			/// <param name="port">The port.</param>
			/// <param name="scopeId">The scope identifier for IPv6 addresses.</param>
			/// <exception cref="ArgumentOutOfRangeException">addr</exception>
			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));
			}

			/// <summary>Initializes a new instance of the <see cref="SOCKADDR"/> class.</summary>
			/// <param name="addr">The <see cref="SOCKADDR_IN"/> value to assign.</param>
			public SOCKADDR(SOCKADDR_IN addr) : base(Marshal.SizeOf(typeof(SOCKADDR_IN))) => Marshal.StructureToPtr(addr, handle, false);

			/// <summary>Initializes a new instance of the <see cref="SOCKADDR"/> class.</summary>
			/// <param name="addr">The <see cref="SOCKADDR_IN6"/> value to assign.</param>
			public SOCKADDR(SOCKADDR_IN6 addr) : base(Marshal.SizeOf(typeof(SOCKADDR_IN6))) => Marshal.StructureToPtr(addr, handle, false);

			/// <summary>Initializes a new instance of the <see cref="SOCKADDR"/> class.</summary>
			/// <param name="ipAddress">The ip address.</param>
			public SOCKADDR(IPAddress ipAddress) : this(ipAddress.GetAddressBytes()) { }

			/// <summary>Initializes a new instance of the <see cref="SOCKADDR"/> class.</summary>
			/// <param name="endPoint">The socket address.</param>
			public SOCKADDR(IPEndPoint endPoint) : this(endPoint.Address.GetAddressBytes(), (ushort)endPoint.Port) { }

			/// <summary>Gets an instance that represents an empty address.</summary>
			public static SOCKADDR Empty => new SOCKADDR(new byte[Marshal.SizeOf(typeof(IN6_ADDR))]);

			/// <summary>Provides a copy of <see cref="SOCKADDR"/> as an array of bytes.</summary>
			/// <value>The array of bytes from this instance.</value>
			public byte[] GetAddressBytes() => GetBytes(0, Size);

			/// <summary>Gets the data behind this address as a byte array.</summary>
			/// <value>The address data.</value>
			public byte[] sa_data => GetBytes(2, 14);

			/// <summary>Gets the <see cref="ADDRESS_FAMILY"/> of this address.</summary>
			/// <value>The address family.</value>
			public ADDRESS_FAMILY sa_family => (ADDRESS_FAMILY)handle.ToStructure<ushort>();

			/// <summary>Allocates from unmanaged memory sufficient memory to hold an object of type T.</summary>
			/// <typeparam name="T">Native type</typeparam>
			/// <param name="value">The value.</param>
			/// <returns><see cref="SOCKADDR"/> object to an native (unmanaged) memory block the size of T.</returns>
			public static SOCKADDR CreateFromStructure<T>(T value = default) => new SOCKADDR(InteropExtensions.MarshalToPtr(value, mm.AllocMem, out int s), true, s);

			/// <summary>Performs an explicit conversion from <see cref="SOCKADDR"/> to <see cref="SOCKADDR_IN"/>.</summary>
			/// <param name="addr">The address.</param>
			/// <returns>The resulting <see cref="SOCKADDR_IN"/> instance from the conversion.</returns>
			/// <exception cref="InvalidCastException"></exception>
			public static explicit operator SOCKADDR_IN(SOCKADDR addr) => addr.sa_family == ADDRESS_FAMILY.AF_INET ? addr.handle.ToStructure<SOCKADDR_IN>() : throw new InvalidCastException();

			/// <summary>Performs an explicit conversion from <see cref="SOCKADDR"/> to <see cref="SOCKADDR_IN6"/>.</summary>
			/// <param name="addr">The address.</param>
			/// <returns>The resulting <see cref="SOCKADDR_IN6"/> instance from the conversion.</returns>
			/// <exception cref="InvalidCastException"></exception>
			public static explicit operator SOCKADDR_IN6(SOCKADDR addr) => addr.sa_family == ADDRESS_FAMILY.AF_INET6 ? addr.handle.ToStructure<SOCKADDR_IN6>() : throw new InvalidCastException();

			/// <summary>Performs an implicit conversion from <see cref="SOCKADDR_IN"/> to <see cref="SOCKADDR"/>.</summary>
			/// <param name="addr">The address.</param>
			/// <returns>The resulting <see cref="SOCKADDR"/> instance from the conversion.</returns>
			public static implicit operator SOCKADDR(SOCKADDR_IN addr) => new SOCKADDR(addr);

			/// <summary>Performs an implicit conversion from <see cref="SOCKADDR_IN6"/> to <see cref="SOCKADDR"/>.</summary>
			/// <param name="addr">The address.</param>
			/// <returns>The resulting <see cref="SOCKADDR"/> instance from the conversion.</returns>
			public static implicit operator SOCKADDR(SOCKADDR_IN6 addr) => new SOCKADDR(addr);

			/// <summary>Performs an implicit conversion from <see cref="SOCKADDR"/> to <see cref="IntPtr"/>.</summary>
			/// <param name="addr">The address.</param>
			/// <returns>The resulting <see cref="IntPtr"/> instance from the conversion.</returns>
			public static implicit operator IntPtr(SOCKADDR addr) => addr.DangerousGetHandle();

			/// <inheritdoc/>
			public override string ToString() => sa_family == ADDRESS_FAMILY.AF_INET ? ((SOCKADDR_IN)this).ToString() : ((SOCKADDR_IN6)this).ToString();
		}
	}
}