Separated WSA code into multiple files, changed return codes to SocketError (from .NET core libs) and added error handling functions.

pull/303/head
dahall 2022-07-10 17:30:38 -06:00
parent 51bd754440
commit 78cabaa31f
4 changed files with 1017 additions and 956 deletions

View File

@ -0,0 +1,391 @@
#pragma warning disable IDE1006 // Naming Styles
using System;
using System.Data;
using System.Runtime.InteropServices;
using System.Text;
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>The CompletionRoutine is a placeholder for an application-defined or library-defined function name.</summary>
/// <param name="dwError">Specifies the completion status for the overlapped operation as indicated by lpOverlapped.</param>
/// <param name="cbTransferred">Specifies the number of bytes received.</param>
/// <param name="lpOverlapped">The overlapped operation.</param>
/// <param name="dwFlags">Contains information that would have appeared in lpFlags if the receive operation had completed immediately.</param>
// void (CALLBACK* LPWSAOVERLAPPED_COMPLETION_ROUTINE) ( IN DWORD dwError, IN DWORD cbTransferred, IN LPWSAOVERLAPPED lpOverlapped,
// IN DWORD dwFlags );
[PInvokeData("winsock2.h", MSDNShortId = "abaf367a-8f99-478c-a58c-d57e9f9cd8a1")]
public delegate void LPWSAOVERLAPPED_COMPLETION_ROUTINE([In] uint dwError, [In] uint cbTransferred, [In] in WSAOVERLAPPED lpOverlapped, [In] uint dwFlags);
/// <summary>Network events.</summary>
[PInvokeData("winsock2.h", MSDNShortId = "f98a71e4-47fb-47a4-b37e-e4cc801a8f98")]
public enum FD
{
/// <summary>Wants to receive notification of readiness for reading.</summary>
FD_READ = (1 << 0),
/// <summary>Wants to receive notification of readiness for writing.</summary>
FD_WRITE = (1 << 1),
/// <summary>Wants to receive notification of the arrival of OOB data.</summary>
FD_OOB = (1 << 2),
/// <summary>Wants to receive notification of incoming connections.</summary>
FD_ACCEPT = (1 << 3),
/// <summary>Wants to receive notification of completed connection or multipoint join operation.</summary>
FD_CONNECT = (1 << 4),
/// <summary>Wants to receive notification of socket closure.</summary>
FD_CLOSE = (1 << 5),
/// <summary>Wants to receive notification of socket (QoS changes.</summary>
FD_QOS = (1 << 6),
/// <summary>Reserved for future use with socket groups. Want to receive notification of socket group QoS changes.</summary>
FD_GROUP_QOS = (1 << 7),
/// <summary>Wants to receive notification of routing interface changes for the specified destination.</summary>
FD_ROUTING_INTERFACE_CHANGE = (1 << 8),
/// <summary>Wants to receive notification of local address list changes for the address family of the socket.</summary>
FD_ADDRESS_LIST_CHANGE = (1 << 9),
/// <summary>All events.</summary>
FD_ALL_EVENTS = ((1 << 10) - 1)
}
/// <summary>Flags to indicate that the socket is acting as a sender (JL_SENDER_ONLY), receiver (JL_RECEIVER_ONLY), or both (JL_BOTH).</summary>
[PInvokeData("winsock2.h", MSDNShortId = "ef9efa03-feed-4f0d-b874-c646cce745c9")]
[Flags]
public enum JL
{
/// <summary>Acting as a sender.</summary>
JL_SENDER_ONLY = 0x01,
/// <summary>Acting as a receiver.</summary>
JL_RECEIVER_ONLY = 0x02,
/// <summary>Acting as both sender and receiver.</summary>
JL_BOTH = 0x04,
}
/// <summary>Flags that control the depth of the search.</summary>
[PInvokeData("winsock2.h", MSDNShortId = "448309ef-b9dd-4960-8016-d26691df59ec")]
[Flags]
public enum LUP : uint
{
/// <summary>Queries deep as opposed to just the first level.</summary>
LUP_DEEP = 0x0001,
/// <summary>Returns containers only.</summary>
LUP_CONTAINERS = 0x0002,
/// <summary>Do not return containers.</summary>
LUP_NOCONTAINERS = 0x0004,
/// <summary>If possible, returns results in the order of distance. The measure of distance is provider specific.</summary>
LUP_NEAREST = 0x0008,
/// <summary>Retrieves the name as lpszServiceInstanceName.</summary>
LUP_RETURN_NAME = 0x0010,
/// <summary>Retrieves the type as lpServiceClassId.</summary>
LUP_RETURN_TYPE = 0x0020,
/// <summary>Retrieves the version as lpVersion.</summary>
LUP_RETURN_VERSION = 0x0040,
/// <summary>Retrieves the comment as lpszComment.</summary>
LUP_RETURN_COMMENT = 0x0080,
/// <summary>Retrieves the addresses as lpcsaBuffer.</summary>
LUP_RETURN_ADDR = 0x0100,
/// <summary>Retrieves the private data as lpBlob.</summary>
LUP_RETURN_BLOB = 0x0200,
/// <summary>
/// Any available alias information is to be returned in successive calls to WSALookupServiceNext, and each alias returned will
/// have the RESULT_IS_ALIAS flag set.
/// </summary>
LUP_RETURN_ALIASES = 0x0400,
/// <summary>Retrieves the query string used for the request.</summary>
LUP_RETURN_QUERY_STRING = 0x0800,
/// <summary>A set of flags that retrieves all of the LUP_RETURN_* values.</summary>
LUP_RETURN_ALL = 0x0FF0,
/// <summary>If the provider has cached information, ignore the cache and query the namespace itself.</summary>
LUP_FLUSHCACHE = 0x1000,
/// <summary>
/// Used as a value for the dwControlFlags parameter in NSPLookupServiceNext. Setting this flag instructs the provider to
/// discard the last result set, which was too large for the supplied buffer, and move on to the next result set.
/// </summary>
LUP_FLUSHPREVIOUS = 0x2000,
/// <summary>Indicates that the namespace provider should included non-authoritative results for names.</summary>
LUP_NON_AUTHORITATIVE = 0x4000,
/// <summary>
/// Indicates whether prime response is in the remote or local part of CSADDR_INFO structure. The other part must be usable in
/// either case. This option applies only to service instance requests.
/// </summary>
LUP_RES_SERVICE = 0x8000,
/// <summary>Indicates that the namespace provider should use a secure query. This option only applies to name query requests.</summary>
LUP_SECURE = 0x8000,
/// <summary>Indicates that the namespace provider should return only preferred names.</summary>
LUP_RETURN_PREFERRED_NAMES = 0x10000,
/// <summary>Indicates that the namespace provider should return the address configuration.</summary>
LUP_ADDRCONFIG = 0x100000,
/// <summary>
/// Indicates that the namespace provider should return the dual addresses. This option only applies to dual-mode sockets (IPv6
/// and IPv4 mapped addresses).
/// </summary>
LUP_DUAL_ADDR = 0x200000,
/// <summary/>
LUP_DNS_ONLY = 0x20000,
/// <summary/>
LUP_FILESERVER = 0x00400000,
/// <summary>
/// Indicates that the namespace provider should disable automatic International Domain Names encoding. This value is supported
/// on Windows 8 and Windows Server 2012
/// </summary>
LUP_DISABLE_IDN_ENCODING = 0x00800000,
/// <summary/>
LUP_API_ANSI = 0x01000000,
/// <summary/>
LUP_RESOLUTION_HANDLE = 0x80000000,
}
/// <summary>
/// The lpFlags parameter can be used to influence the behavior of the function invocation beyond the options specified for the
/// associated socket. That is, the semantics of this function are determined by the socket options and the lpFlags parameter.
/// </summary>
[PInvokeData("winsock2.h", MSDNShortId = "bfe66e11-e9a7-4321-ad55-3141113e9a03")]
[Flags]
public enum MsgFlags
{
/// <summary>Processes OOB data.</summary>
MSG_OOB = 0x1,
/// <summary>
/// Peeks at the incoming data. The data is copied into the buffer, but is not removed from the input queue. This flag is valid
/// only for nonoverlapped sockets.
/// </summary>
MSG_PEEK = 0x2,
/// <summary/>
MSG_DONTROUTE = 0x4,
/// <summary>
/// The receive request will complete only when one of the following events occurs: Be aware that if the underlying transport
/// provider does not support MSG_WAITALL, or if the socket is in a non-blocking mode, then this call will fail with
/// WSAEOPNOTSUPP. Also, if MSG_WAITALL is specified along with MSG_OOB, MSG_PEEK, or MSG_PARTIAL, then this call will fail with
/// WSAEOPNOTSUPP. This flag is not supported on datagram sockets or message-oriented sockets.
/// </summary>
MSG_WAITALL = 0x8,
/// <summary>
/// This flag is for stream-oriented sockets only. This flag allows an application that uses stream sockets to tell the
/// transport provider not to delay completion of partially filled pending receive requests. This is a hint to the transport
/// provider that the application is willing to receive any incoming data as soon as possible without necessarily waiting for
/// the remainder of the data that might still be in transit. What constitutes a partially filled pending receive request is a
/// transport-specific matter. In the case of TCP, this refers to the case of incoming TCP segments being placed into the
/// receive request data buffer where none of the TCP segments indicated a PUSH bit value of 1. In this case, TCP may hold the
/// partially filled receive request a little longer to allow the remainder of the data to arrive with a TCP segment that has
/// the PUSH bit set to 1. This flag tells TCP not to hold the receive request but to complete it immediately. Using this flag
/// for large block transfers is not recommended since processing partial blocks is often not optimal. This flag is useful only
/// for cases where receiving and processing the partial data immediately helps decrease processing latency. This flag is a hint
/// rather than an actual guarantee. This flag is supported on Windows 8.1, Windows Server 2012 R2, and later.
/// </summary>
MSG_PUSH_IMMEDIATE = 0x20,
/// <summary>
/// This flag is for message-oriented sockets only. On output, this flag indicates that the data specified is a portion of the
/// message transmitted by the sender. Remaining portions of the message will be specified in subsequent receive operations. A
/// subsequent receive operation with the MSG_PARTIAL flag cleared indicates end of sender's message. As an input parameter,
/// this flag indicates that the receive operation should complete even if only part of a message has been received by the
/// transport provider.
/// </summary>
MSG_PARTIAL = 0x8000,
/// <summary/>
MSG_INTERRUPT = 0x10,
/// <summary>The datagram was truncated. More data was present than the process allocated room for.</summary>
MSG_TRUNC = 0x0100,
/// <summary>The control (ancillary) data was truncated. More control data was present than the process allocated room for.</summary>
MSG_CTRUNC = 0x0200,
/// <summary>The datagram was received as a link-layer broadcast or with a destination IP address that is a broadcast address.</summary>
MSG_BCAST = 0x0400,
/// <summary>The datagram was received with a destination IP address that is a multicast address.</summary>
MSG_MCAST = 0x0800,
/// <summary>
/// This flag specifies that queued errors should be received from the socket error queue. The error is passed in an ancillary
/// message with a type dependent on the protocol (for IPv4 IP_RECVERR). The user should supply a buffer of sufficient size.See
/// cmsg(3) and ip(7) for more information.The payload of the original packet that caused the error is passed as normal data via
/// msg_iovec. The original destination address of the datagram that caused the error is supplied via msg_name.
/// </summary>
MSG_ERRQUEUE = 0x1000,
}
/// <summary>
/// A set of flags that indicate the type of status being requested or, upon return from the WSAPoll function call, the results of
/// the status query.
/// </summary>
[PInvokeData("winsock2.h", MSDNShortId = "88f122ce-e2ca-44ce-bd53-d73d0962e7ef")]
[Flags]
public enum PollFlags : short
{
/// <summary>Normal data may be read without blocking.</summary>
POLLRDNORM = 0x0100,
/// <summary>Priority band (out-of-band) data may be read without blocking.</summary>
POLLRDBAND = 0x0200,
/// <summary>POLLRDNORM | POLLRDBAND</summary>
POLLIN = (POLLRDNORM | POLLRDBAND),
/// <summary>Priority data may be read without blocking. This flag is not returned by the Microsoft Winsock provider.</summary>
POLLPRI = 0x0400,
/// <summary>Normal data may be written without blocking.</summary>
POLLWRNORM = 0x0010,
/// <summary>Normal data may be written without blocking.</summary>
POLLOUT = (POLLWRNORM),
/// <summary/>
POLLWRBAND = 0x0020,
/// <summary>An error has occurred.</summary>
POLLERR = 0x0001,
/// <summary>A stream-oriented connection was either disconnected or aborted.</summary>
POLLHUP = 0x0002,
/// <summary>An invalid socket was used.</summary>
POLLNVAL = 0x0004,
}
/// <summary>Service install flags value that further controls the operation performed of the WSASetServicefunction.</summary>
[PInvokeData("winsock2.h", MSDNShortId = "21a8ff26-4c9e-4846-a75a-1a27c746edab")]
[Flags]
public enum ServiceInstallFlags
{
/// <summary>
/// Controls scope of operation. When this flag is not set, service addresses are managed as a group. A register or removal from
/// the registry invalidates all existing addresses before adding the given address set. When set, the action is only performed
/// on the given address set. A register does not invalidate existing addresses and a removal from the registry only invalidates
/// the given set of addresses.
/// </summary>
SERVICE_MULTIPLE = 0x00000001,
}
/// <summary>A set of flags used to specify additional socket attributes.</summary>
[PInvokeData("winsock2.h", MSDNShortId = "dcf2e543-de54-43d9-9e45-4cb935da3548")]
[Flags]
public enum WSA_FLAG
{
/// <term>
/// Create a socket that supports overlapped I/O operations. Most sockets should be created with this flag set. Overlapped
/// sockets can utilize WSASend, WSASendTo, WSARecv, WSARecvFrom, and WSAIoctl for overlapped I/O operations, which allow
/// multiple operations to be initiated and in progress simultaneously. All functions that allow overlapped operation (WSASend,
/// WSARecv, WSASendTo, WSARecvFrom, WSAIoctl) also support nonoverlapped usage on an overlapped socket if the values for
/// parameters related to overlapped operations are NULL.
/// </term>
WSA_FLAG_OVERLAPPED = 0x01,
/// <term>
/// Create a socket that will be a c_root in a multipoint session. This attribute is only allowed if the WSAPROTOCOL_INFO
/// structure for the transport provider that creates the socket supports a multipoint or multicast mechanism and the control
/// plane for a multipoint session is rooted. This would be indicated by the dwServiceFlags1 member of the WSAPROTOCOL_INFO
/// structure with the XP1_SUPPORT_MULTIPOINT and XP1_MULTIPOINT_CONTROL_PLANE flags set. When the lpProtocolInfo parameter is
/// not NULL, the WSAPROTOCOL_INFO structure for the transport provider is pointed to by the lpProtocolInfo parameter. When the
/// lpProtocolInfo parameter is NULL, the WSAPROTOCOL_INFO structure is based on the transport provider selected by the values
/// specified for the af, type, and protocol parameters. Refer to Multipoint and Multicast Semantics for additional information
/// on a multipoint session.
/// </term>
WSA_FLAG_MULTIPOINT_C_ROOT = 0x02,
/// <term>
/// Create a socket that will be a c_leaf in a multipoint session. This attribute is only allowed if the WSAPROTOCOL_INFO
/// structure for the transport provider that creates the socket supports a multipoint or multicast mechanism and the control
/// plane for a multipoint session is non-rooted. This would be indicated by the dwServiceFlags1 member of the WSAPROTOCOL_INFO
/// structure with the XP1_SUPPORT_MULTIPOINT flag set and the XP1_MULTIPOINT_CONTROL_PLANE flag not set. When the
/// lpProtocolInfo parameter is not NULL, the WSAPROTOCOL_INFO structure for the transport provider is pointed to by the
/// lpProtocolInfo parameter. When the lpProtocolInfo parameter is NULL, the WSAPROTOCOL_INFO structure is based on the
/// transport provider selected by the values specified for the af, type, and protocol parameters. Refer to Multipoint and
/// Multicast Semantics for additional information on a multipoint session.
/// </term>
WSA_FLAG_MULTIPOINT_C_LEAF = 0x04,
/// <term>
/// Create a socket that will be a d_root in a multipoint session. This attribute is only allowed if the WSAPROTOCOL_INFO
/// structure for the transport provider that creates the socket supports a multipoint or multicast mechanism and the data plane
/// for a multipoint session is rooted. This would be indicated by the dwServiceFlags1 member of the WSAPROTOCOL_INFO structure
/// with the XP1_SUPPORT_MULTIPOINT and XP1_MULTIPOINT_DATA_PLANE flags set. When the lpProtocolInfo parameter is not NULL, the
/// WSAPROTOCOL_INFO structure for the transport provider is pointed to by the lpProtocolInfo parameter. When the lpProtocolInfo
/// parameter is NULL, the WSAPROTOCOL_INFO structure is based on the transport provider selected by the values specified for
/// the af, type, and protocol parameters. Refer to Multipoint and Multicast Semantics for additional information on a
/// multipoint session.
/// </term>
WSA_FLAG_MULTIPOINT_D_ROOT = 0x08,
/// <term>
/// Create a socket that will be a d_leaf in a multipoint session. This attribute is only allowed if the WSAPROTOCOL_INFO
/// structure for the transport provider that creates the socket supports a multipoint or multicast mechanism and the data plane
/// for a multipoint session is non-rooted. This would be indicated by the dwServiceFlags1 member of the WSAPROTOCOL_INFO
/// structure with the XP1_SUPPORT_MULTIPOINT flag set and the XP1_MULTIPOINT_DATA_PLANE flag not set. When the lpProtocolInfo
/// parameter is not NULL, the WSAPROTOCOL_INFO structure for the transport provider is pointed to by the lpProtocolInfo
/// parameter. When the lpProtocolInfo parameter is NULL, the WSAPROTOCOL_INFO structure is based on the transport provider
/// selected by the values specified for the af, type, and protocol parameters. Refer to Multipoint and Multicast Semantics for
/// additional information on a multipoint session.
/// </term>
WSA_FLAG_MULTIPOINT_D_LEAF = 0x10,
/// <term>
/// Create a socket that allows the the ability to set a security descriptor on the socket that contains a security access
/// control list (SACL) as opposed to just a discretionary access control list (DACL). SACLs are used for generating audits and
/// alarms when an access check occurs on the object. For a socket, an access check occurs to determine whether the socket
/// should be allowed to bind to a specific address specified to the bind function. The ACCESS_SYSTEM_SECURITY access right
/// controls the ability to get or set the SACL in an object's security descriptor. The system grants this access right only if
/// the SE_SECURITY_NAME privilege is enabled in the access token of the requesting thread.
/// </term>
WSA_FLAG_ACCESS_SYSTEM_SECURITY = 0x40,
/// <term>
/// Create a socket that is non-inheritable. A socket handle created by the WSASocket or the socket function is inheritable by
/// default. When this flag is set, the socket handle is non-inheritable. The GetHandleInformation function can be used to
/// determine if a socket handle was created with the WSA_FLAG_NO_HANDLE_INHERIT flag set. The GetHandleInformation function
/// will return that the HANDLE_FLAG_INHERIT value is set. This flag is supported on Windows 7 with SP1, Windows Server 2008 R2
/// with SP1, and later
/// </term>
WSA_FLAG_NO_HANDLE_INHERIT = 0x80,
/// <summary/>
WSA_FLAG_REGISTERED_IO = 0x100,
}
}
}

View File

@ -0,0 +1,33 @@
using System;
using System.Net.Sockets;
using System.Security;
namespace Vanara.PInvoke
{
public static partial class Ws2_32
{
/// <summary>
/// Throws an appropriate exception if <paramref name="err"/> is a failure. If the value of <paramref name="err"/> equals <see
/// cref="SocketError.SocketError"/> (-1 or SOCKET_ERROR), then <see cref="WSAGetLastError"/> is called to retrive the actual error.
/// </summary>
/// <param name="err">The <see cref="SocketError"/> value to process.</param>
public static void ThrowIfFailed(this SocketError err) { var ex = err.GetException(); if (ex is not null) throw ex; }
/// <summary>Throws the last error if the function returns <see langword="false"/>.</summary>
/// <param name="value">The value to check.</param>
public static void ThrowLastErrorIfFalse(bool value) { if (!value) throw WSAGetLastError().GetException(); }
/// <summary>
/// Gets the .NET <see cref="Exception"/> associated with the <see cref="SocketError"/> value and optionally adds the supplied message.
/// </summary>
/// <param name="err">The <see cref="SocketError"/> value to process.</param>
/// <returns>The associated <see cref="Exception"/> or <see langword="null"/> if this <see cref="SocketError"/> is not a failure.</returns>
[SecurityCritical, SecuritySafeCritical]
public static Exception GetException(this SocketError err) => err switch
{
0 => null,
SocketError.SocketError => new SocketException((int)WSAGetLastError()),
_ => new SocketException((int)err)
};
}
}

View File

@ -0,0 +1,487 @@
#pragma warning disable IDE1006 // Naming Styles
using System;
using System.Data;
using System.Runtime.InteropServices;
using Vanara.InteropServices;
namespace Vanara.PInvoke
{
/// <summary>Functions, structures and constants from ws2_32.h.</summary>
public static partial class Ws2_32
{
/// <summary>
/// The <c>fd_set</c> structure is used by various Windows Sockets functions and service providers, such as the select function, to
/// place sockets into a "set" for various purposes, such as testing a given socket for readability using the readfds parameter of
/// the <c>select</c> function.
/// </summary>
// https://docs.microsoft.com/en-us/windows/win32/api/winsock/ns-winsock-fd_set typedef struct fd_set { u_int fd_count; SOCKET
// fd_array[FD_SETSIZE]; } fd_set, FD_SET, *PFD_SET, *LPFD_SET;
[PInvokeData("winsock.h", MSDNShortId = "2af5d69d-190e-4814-8d8b-438431808625")]
[StructLayout(LayoutKind.Sequential)]
public struct fd_set
{
/// <summary>The number of sockets in the set.</summary>
public uint fd_count;
/// <summary>An array of sockets that are in the set.</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
public SOCKET[] fd_array;
}
/// <summary>The <c>WSANETWORKEVENTS</c> structure is used to store a socket's internal information about network events.</summary>
// https://docs.microsoft.com/en-us/windows/win32/api/winsock2/ns-winsock2-wsanetworkevents typedef struct _WSANETWORKEVENTS { long
// lNetworkEvents; int iErrorCode[FD_MAX_EVENTS]; } WSANETWORKEVENTS, *LPWSANETWORKEVENTS;
[PInvokeData("winsock2.h", MSDNShortId = "72ae4aa8-4e15-4215-8dcb-45e394ac1313")]
[StructLayout(LayoutKind.Sequential)]
public struct WSANETWORKEVENTS
{
/// <summary>Indicates which of the FD_XXX network events have occurred.</summary>
public int lNetworkEvents;
/// <summary>
/// Array that contains any associated error codes, with an array index that corresponds to the position of event bits in
/// <c>lNetworkEvents</c>. The identifiers FD_READ_BIT, FD_WRITE_BIT and others can be used to index the <c>iErrorCode</c> array.
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public int[] iErrorCode;
}
/// <summary>The <c>WSANSCLASSINFO</c> structure provides individual parameter information for a specific Windows Sockets namespace.</summary>
/// <remarks>
/// The <c>WSANSCLASSINFO</c> structure is defined differently depending on whether ANSI or UNICODE is used. The above syntax block
/// applies to ANSI; for UNICODE, the datatype for <c>lpszName</c> is <c>LPWSTR</c>.
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/winsock2/ns-winsock2-wsansclassinfoa typedef struct _WSANSClassInfoA { LPSTR
// lpszName; DWORD dwNameSpace; DWORD dwValueType; DWORD dwValueSize; LPVOID lpValue; } WSANSCLASSINFOA, *PWSANSCLASSINFOA, *LPWSANSCLASSINFOA;
[PInvokeData("winsock2.h", MSDNShortId = "b4f811ad-7967-45bd-b563-a28bb1633596")]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct WSANSCLASSINFO
{
/// <summary>String value associated with the parameter, such as SAPID, TCPPORT, and so forth.</summary>
[MarshalAs(UnmanagedType.LPStr)]
public string lpszName;
/// <summary>GUID associated with the namespace.</summary>
public uint dwNameSpace;
/// <summary>Value type for the parameter, such as REG_DWORD or REG_SZ, and so forth.</summary>
public uint dwValueType;
/// <summary>Size of the parameter provided in <c>lpValue</c>, in bytes.</summary>
public uint dwValueSize;
/// <summary>Pointer to the value of the parameter.</summary>
public IntPtr lpValue;
}
/// <summary>The <c>WSAPOLLFD</c> structure stores socket information used by the WSAPoll function.</summary>
/// <remarks>
/// <para>The <c>WSAPOLLFD</c> structure is defined on Windows Vista and later.</para>
/// <para>
/// The <c>WSAPOLLFD</c> structure is used by the WSAPoll function to determine the status of one or more sockets. The set of
/// sockets for which status is requested is specified in fdarray parameter, which is an array of <c>WSAPOLLFD</c> structures. An
/// application sets the appropriate flags in the <c>events</c> member of the <c>WSAPOLLFD</c> structure to specify the type of
/// status requested for each corresponding socket. The <c>WSAPoll</c> function returns the status of a socket in the <c>revents</c>
/// member of the <c>WSAPOLLFD</c> structure.
/// </para>
/// <para>
/// If the <c>fd</c> member of the <c>WSAPOLLFD</c> structure is set to a negative value, the structure is ignored by the WSAPoll
/// function call, and the <c>revents</c> member is cleared upon return. This is useful to applications that maintain a fixed
/// allocation for the fdarray parameter of <c>WSAPoll</c>; such applications need not waste resources compacting elements of the
/// array for unused entries or reallocating memory. It is unnecessary to clear the <c>revents</c> member prior to calling the
/// <c>WSAPoll</c> function.
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/winsock2/ns-winsock2-wsapollfd typedef struct pollfd { SOCKET fd; SHORT
// events; SHORT revents; } WSAPOLLFD, *PWSAPOLLFD, *LPWSAPOLLFD;
[PInvokeData("winsock2.h", MSDNShortId = "88f122ce-e2ca-44ce-bd53-d73d0962e7ef")]
[StructLayout(LayoutKind.Sequential)]
public struct WSAPOLLFD
{
/// <summary>
/// <para>Type: <c>SOCKET</c></para>
/// <para>The identifier of the socket for which to find status. This parameter is ignored if set to a negative value. See Remarks.</para>
/// </summary>
public SOCKET fd;
/// <summary>
/// <para>Type: <c>short</c></para>
/// <para>A set of flags indicating the type of status being requested. This must be one or more of the following.</para>
/// <list type="table">
/// <listheader>
/// <term>Flag</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>POLLPRI</term>
/// <term>Priority data may be read without blocking. This flag is not supported by the Microsoft Winsock provider.</term>
/// </item>
/// <item>
/// <term>POLLRDBAND</term>
/// <term>Priority band (out-of-band) data can be read without blocking.</term>
/// </item>
/// <item>
/// <term>POLLRDNORM</term>
/// <term>Normal data can be read without blocking.</term>
/// </item>
/// <item>
/// <term>POLLWRNORM</term>
/// <term>Normal data can be written without blocking.</term>
/// </item>
/// </list>
/// <para>
/// The POLLIN flag is defined as the combination of the <c>POLLRDNORM</c> and <c>POLLRDBAND</c> flag values. The POLLOUT flag
/// is defined as the same as the <c>POLLWRNORM</c> flag value.
/// </para>
/// </summary>
public PollFlags events;
/// <summary>
/// <para>Type: <c>short</c></para>
/// <para>
/// A set of flags that indicate, upon return from the WSAPoll function call, the results of the status query. This can a
/// combination of the following flags.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Flag</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>POLLERR</term>
/// <term>An error has occurred.</term>
/// </item>
/// <item>
/// <term>POLLHUP</term>
/// <term>A stream-oriented connection was either disconnected or aborted.</term>
/// </item>
/// <item>
/// <term>POLLNVAL</term>
/// <term>An invalid socket was used.</term>
/// </item>
/// <item>
/// <term>POLLPRI</term>
/// <term>Priority data may be read without blocking. This flag is not returned by the Microsoft Winsock provider.</term>
/// </item>
/// <item>
/// <term>POLLRDBAND</term>
/// <term>Priority band (out-of-band) data may be read without blocking.</term>
/// </item>
/// <item>
/// <term>POLLRDNORM</term>
/// <term>Normal data may be read without blocking.</term>
/// </item>
/// <item>
/// <term>POLLWRNORM</term>
/// <term>Normal data may be written without blocking.</term>
/// </item>
/// </list>
/// <para>
/// The POLLIN flag is defined as the combination of the <c>POLLRDNORM</c> and <c>POLLRDBAND</c> flag values. The POLLOUT flag
/// is defined as the same as the <c>POLLWRNORM</c> flag value.
/// </para>
/// <para>
/// For sockets that do not satisfy the status query, and have no error, the <c>revents</c> member is set to zero upon return.
/// </para>
/// </summary>
public PollFlags revents;
}
/// <summary>
/// The <c>WSAQUERYSET</c> structure provides relevant information about a given service, including service class ID, service name,
/// applicable namespace identifier and protocol information, as well as a set of transport addresses at which the service listens.
/// </summary>
/// <remarks>
/// <para>
/// The <c>WSAQUERYSET</c> structure is used as part of the original namespace provider version 1 architecture available on Windows
/// 95 and later. A newer version 2 of the namespace architecture is available on Windows Vista and later.
/// </para>
/// <para>
/// In most instances, applications interested in only a particular transport protocol should constrain their query by address
/// family and protocol rather than by namespace. This would allow an application that needs to locate a TCP/IP service, for
/// example, to have its query processed by all available namespaces such as the local hosts file, DNS, and NIS.
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/winsock2/ns-winsock2-wsaquerysetw typedef struct _WSAQuerySetW { DWORD dwSize;
// LPWSTR lpszServiceInstanceName; LPGUID lpServiceClassId; LPWSAVERSION lpVersion; LPWSTR lpszComment; DWORD dwNameSpace; LPGUID
// lpNSProviderId; LPWSTR lpszContext; DWORD dwNumberOfProtocols; LPAFPROTOCOLS lpafpProtocols; LPWSTR lpszQueryString; DWORD
// dwNumberOfCsAddrs; LPCSADDR_INFO lpcsaBuffer; DWORD dwOutputFlags; LPBLOB lpBlob; } WSAQUERYSETW, *PWSAQUERYSETW, *LPWSAQUERYSETW;
[PInvokeData("winsock2.h", MSDNShortId = "6c81fbba-aaf4-49ca-ab79-b6fe5dfb0076")]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct WSAQUERYSET
{
/// <summary>
/// <para>Type: <c>DWORD</c></para>
/// <para>
/// The size, in bytes, of the <c>WSAQUERYSET</c> structure. This member is used as a versioning mechanism since the size of the
/// <c>WSAQUERYSET</c> structure has changed on later versions of Windows.
/// </para>
/// </summary>
public uint dwSize;
/// <summary>
/// <para>Type: <c>LPTSTR</c></para>
/// <para>
/// A pointer to an optional NULL-terminated string that contains service name. The semantics for using wildcards within the
/// string are not defined, but can be supported by certain namespace providers.
/// </para>
/// </summary>
[MarshalAs(UnmanagedType.LPTStr)] public string lpszServiceInstanceName;
/// <summary>
/// <para>Type: <c>LPGUID</c></para>
/// <para>The GUID corresponding to the service class. This member is required to be set.</para>
/// </summary>
public GuidPtr lpServiceClassId;
/// <summary>
/// <para>Type: <c>LPWSAVERSION</c></para>
/// <para>
/// A pointer to an optional desired version number of the namespace provider. This member provides version comparison semantics
/// (that is, the version requested must match exactly, or version must be not less than the value supplied).
/// </para>
/// </summary>
public IntPtr lpVersion;
/// <summary>
/// <para>Type: <c>LPTSTR</c></para>
/// <para>This member is ignored for queries.</para>
/// </summary>
[MarshalAs(UnmanagedType.LPTStr)] public string lpszComment;
/// <summary>
/// <para>Type: <c>DWORD</c></para>
/// <para>
/// A namespace identifier that determines which namespace providers are queried. Passing a specific namespace identifier will
/// result in only namespace providers that support the specified namespace being queried. Specifying <c>NS_ALL</c> will result
/// in all installed and active namespace providers being queried.
/// </para>
/// <para>
/// Options for the <c>dwNameSpace</c> member are listed in the Winsock2.h include file. Several new namespace providers are
/// included with Windows Vista and later. Other namespace providers can be installed, so the following possible values are only
/// those commonly available. Many other values are possible.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <term>Meaning</term>
/// </listheader>
/// <item>
/// <term>NS_ALL</term>
/// <term>All installed and active namespaces.</term>
/// </item>
/// <item>
/// <term>NS_BTH</term>
/// <term>The Bluetooth namespace. This namespace identifier is supported on Windows Vista and later.</term>
/// </item>
/// <item>
/// <term>NS_DNS</term>
/// <term>The domain name system (DNS) namespace.</term>
/// </item>
/// <item>
/// <term>NS_EMAIL</term>
/// <term>The email namespace. This namespace identifier is supported on Windows Vista and later.</term>
/// </item>
/// <item>
/// <term>NS_NLA</term>
/// <term>The network location awareness (NLA) namespace. This namespace identifier is supported on Windows XP and later.</term>
/// </item>
/// <item>
/// <term>NS_PNRPNAME</term>
/// <term>
/// The peer-to-peer name space for a specific peer name. This namespace identifier is supported on Windows Vista and later.
/// </term>
/// </item>
/// <item>
/// <term>NS_PNRPCLOUD</term>
/// <term>
/// The peer-to-peer name space for a collection of peer names. This namespace identifier is supported on Windows Vista and later.
/// </term>
/// </item>
/// </list>
/// </summary>
public NS dwNameSpace;
/// <summary>
/// <para>Type: <c>LPGUID</c></para>
/// <para>
/// A pointer to an optional GUID of a specific namespace provider to query in the case where multiple namespace providers are
/// registered under a single namespace such as <c>NS_DNS</c>. Passing the GUID for a specific namespace provider will result in
/// only the specified namespace provider being queried. The WSAEnumNameSpaceProviders and WSAEnumNameSpaceProvidersEx functions
/// can be called to retrieve the GUID for a namespace provider.
/// </para>
/// </summary>
public GuidPtr lpNSProviderId;
/// <summary>
/// <para>Type: <c>LPTSTR</c></para>
/// <para>A pointer to an optional starting point of the query in a hierarchical namespace.</para>
/// </summary>
[MarshalAs(UnmanagedType.LPTStr)] public string lpszContext;
/// <summary>
/// <para>Type: <c>DWORD</c></para>
/// <para>The size, in bytes, of the protocol constraint array. This member can be zero.</para>
/// </summary>
public uint dwNumberOfProtocols;
/// <summary>
/// <para>Type: <c>LPAFPROTOCOLS</c></para>
/// <para>A pointer to an optional array of AFPROTOCOLS structures. Only services that utilize these protocols will be returned.</para>
/// </summary>
public IntPtr lpafpProtocols;
/// <summary>
/// <para>Type: <c>LPTSTR</c></para>
/// <para>
/// A pointer to an optional NULL-terminated query string. Some namespaces, such as Whois++, support enriched SQL-like queries
/// that are contained in a simple text string. This parameter is used to specify that string.
/// </para>
/// </summary>
[MarshalAs(UnmanagedType.LPTStr)] public string lpszQueryString;
/// <summary>
/// <para>Type: <c>DWORD</c></para>
/// <para>This member is ignored for queries.</para>
/// </summary>
public uint dwNumberOfCsAddrs;
/// <summary>
/// <para>Type: <c>LPCSADDR_INFO</c></para>
/// <para>This member is ignored for queries.</para>
/// </summary>
public IntPtr lpcsaBuffer;
/// <summary>
/// <para>Type: <c>DWORD</c></para>
/// <para>This member is ignored for queries.</para>
/// </summary>
public uint dwOutputFlags;
/// <summary>
/// <para>Type: <c>LPBLOB</c></para>
/// <para>
/// An optional pointer to data that is used to query or set provider-specific namespace information. The format of this
/// information is specific to the namespace provider.
/// </para>
/// </summary>
public IntPtr lpBlob;
/// <summary>Initializes a new instance of the <see cref="WSAQUERYSET"/> struct.</summary>
/// <param name="nameSpace">The name space.</param>
public WSAQUERYSET(NS nameSpace) : this()
{
dwSize = (uint)Marshal.SizeOf(this);
dwNameSpace = nameSpace;
}
}
/// <summary>
/// The <c>WSASERVICECLASSINFO</c> structure contains information about a specified service class. For each service class in Windows
/// Sockets 2, there is a single <c>WSASERVICECLASSINFO</c> structure.
/// </summary>
// https://docs.microsoft.com/en-us/windows/win32/api/winsock2/ns-winsock2-wsaserviceclassinfow typedef struct _WSAServiceClassInfoW
// { LPGUID lpServiceClassId; LPWSTR lpszServiceClassName; DWORD dwCount; LPWSANSCLASSINFOW lpClassInfos; } WSASERVICECLASSINFOW,
// *PWSASERVICECLASSINFOW, *LPWSASERVICECLASSINFOW;
[PInvokeData("winsock2.h", MSDNShortId = "02422c24-34a6-4e34-a795-66b0b687ac44")]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct WSASERVICECLASSINFO
{
/// <summary>Unique Identifier (GUID) for the service class.</summary>
public GuidPtr lpServiceClassId;
/// <summary>Well known name associated with the service class.</summary>
[MarshalAs(UnmanagedType.LPTStr)]
public string lpszServiceClassName;
/// <summary>Number of entries in <c>lpClassInfos</c>.</summary>
public uint dwCount;
/// <summary>Array of WSANSCLASSINFO structures that contains information about the service class.</summary>
public IntPtr lpClassInfos;
/// <summary>Marshaled array of WSANSCLASSINFO structures that contains information about the service class.</summary>
public WSANSCLASSINFO[] ClassInfos => lpClassInfos.ToArray<WSANSCLASSINFO>((int)dwCount);
}
/// <summary>Provides a <see cref="SafeHandle"/> for <see cref="WSAEVENT"/> that is disposed using <see cref="WSACloseEvent"/>.</summary>
public class SafeWSAEVENT : SafeHANDLE, ISyncHandle
{
/// <summary>Initializes a new instance of the <see cref="SafeWSAEVENT"/> 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 SafeWSAEVENT(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }
/// <summary>Initializes a new instance of the <see cref="SafeWSAEVENT"/> class.</summary>
private SafeWSAEVENT() : base() { }
/// <summary>Performs an implicit conversion from <see cref="SafeWSAEVENT"/> to <see cref="WSAEVENT"/>.</summary>
/// <param name="h">The safe handle instance.</param>
/// <returns>The result of the conversion.</returns>
public static implicit operator WSAEVENT(SafeWSAEVENT h) => h.handle;
/// <inheritdoc/>
protected override bool InternalReleaseHandle() => WSACloseEvent(handle);
}
/// <summary>
/// A disposable class to manage initialization of the WSA library. See remarks for use.
/// </summary>
/// <example>
/// <code>
/// using (var wsa = SafeWSA.Initialize())
/// {
/// // Call WSA functions...
/// }
/// </code>
/// Or, if you must have a certain version of the library, use the <c>InitDemandVersion</c> static method.
/// <code>
/// using (var wsa = SafeWSA.InitDemandVersion(Macros.MAKEWORD(1, 1)))
/// {
/// // Call WSA functions.
/// // The above call with throw a VersionNotFoundException if that version is not supported.
/// }
/// </code>
/// </example>
/// <seealso cref="System.IDisposable" />
public class SafeWSA : IDisposable
{
private WSADATA data;
private SafeWSA() { }
/// <summary>Initiates use of the Winsock DLL by a process.</summary>
/// <param name="wVersionRequired">The requested version of the WinSock library.</param>
/// <returns>An object that holds the WinSock library while in scope. Upon disposal, <c>WSACleanup</c> is called.</returns>
public static SafeWSA Initialize(ushort wVersionRequired = 0x0202)
{
var ret = new SafeWSA();
WSAStartup(wVersionRequired, out ret.data).ThrowIfFailed();
return ret;
}
/// <summary>
/// Initiates use of the Winsock DLL by a process and throws an exception if <paramref name="wVersionRequired"/> isn't available.
/// </summary>
/// <param name="wVersionRequired">The required version of the WinSock library.</param>
/// <returns>An object that holds the WinSock library while in scope. Upon disposal, <c>WSACleanup</c> is called.</returns>
/// <exception cref="VersionNotFoundException"></exception>
public static SafeWSA DemandVersion(ushort wVersionRequired)
{
var ret = Initialize(wVersionRequired);
if (ret.Data.wVersion != wVersionRequired)
throw new VersionNotFoundException();
return ret;
}
/// <summary>Gets the WSADATA value returned by <c>WSAStartup</c>.</summary>
/// <value>The data.</value>
public WSADATA Data { get => data; private set => data = value; }
void IDisposable.Dispose() => WSACleanup();
}
}
}

File diff suppressed because it is too large Load Diff