Winsock 2 provides a method for determining which protocols are installed on a given workstation and returning a variety of characteristics for each protocol. If a protocol is capable of multiple behaviors, each distinct behavior type has its own catalog entry within the system. For example, if you install TCP/IP on your system, there will be two IP entries: one for TCP, which is reliable and connection-oriented, and one for UDP, which is unreliable and connectionless.
The function call to obtain information on installed network protocols is WSAEnumProtocols and is defined as
int WSAEnumProtocols ( LPINT lpiProtocols, LPWSAPROTOCOL_INFO lpProtocolBuffer, LPDWORD lpdwBufferLength ); |
This function supersedes the Winsock 1.1 function EnumProtocols, which is the necessary function for Windows CE. The only difference is that WSAEnumProtocols returns an array of WSAPROTOCOL_INFO structures, whereas EnumProtocols returns an array of PROTOCOL_INFO structures that contain fewer fields than the WSAPROTOCOL_INFO structure (but more or less the same information). The WSAPROTOCOL_INFO structure is defined as
typedef struct _WSAPROTOCOL_INFOW { 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; WCHAR szProtocol[WSAPROTOCOL_LEN + 1]; } WSAPROTOCOL_INFOW, FAR * LPWSAPROTOCOL_INFOW; |
Initializing WinsockBefore you can call a Winsock function, you must load the correct version of the Winsock library. The Winsock initialization routine is WSAStartup, defined as
int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);The first parameter is the version of the Winsock library that you want to load. For current Win32 platforms, the latest Winsock 2 library is version 2.2. The only exception is Windows CE, which supports only Winsock version 1.1. If you wanted Winsock version 2.2, you could either specify the value (0x0202) or use the macro MAKEWORD(2, 2). The high-order byte specifies the minor version number, while the low-order byte specifies the major version number.
The second parameter is a structure, WSADATA, that is returned upon completion. WSADATA contains information about the version of Winsock that WSAStartup loaded. Table 5-2 lists the individual fields of the WSADATA structure, which is actually defined as
typedef struct WSAData { WORD wVersion; WORD wHighVersion; char szDescription[WSADESCRIPTION_LEN + 1]; char szSystemStatus[WSASYS_STATUS_LEN + 1]; unsigned short iMaxSockets; unsigned short iMaxUdpDg; char FAR * lpVendorInfo; } WSADATA, FAR * LPWSADATA;For the most part, the only useful information returned in the WSADATA structure is wVersion and wHighVersion. The entries pertaining to maximum sockets and maximum UDP size should be obtained from the catalog entry for the specific protocol you are using. The above section on WSAEnumProtocols discusses this.
Table 5-2. Member fields of the WSADATA structure
Field Description wVersion The Winsock version the caller is expected to use wHighVersion The highest Winsock version supported by the loaded library, usually the same value as wVersion szDescription A text description of the loaded library szSystemStatus A text string containing relevant status or configuration information iMaxSockets Maximum number of sockets (ignore this field for Winsock 2 or later) iMaxUdpDg Maximum UDP datagram size (ignore this field for Winsock 2 or later) lpVendorInfo Vendor-specific information (ignore this field for Winsock 2 or later) When you are finished with the Winsock library and no longer want to call any Winsock functions, the companion routine WSACleanup unloads the library and frees any resources. This function is defined as
int WSACleanup (void);Keep in mind that for each call to WSAStartup a matching call to WSACleanup will be needed because each startup call increments the reference count to the loaded Winsock DLL, requiring an equal number of calls to WSACleanup to decrement the count.
Note that Winsock 2 is fully compatible with all Winsock 1.1 function calls. Thus an application written to the Winsock 1.1 specification will be able to run if it loads the Winsock 2 library, as the Winsock 1.1 functions are mapped through their Winsock 2 equivalents.
The easiest way to call WSAEnumProtocols is to make the first call with lpProtocolBuffer equal to NULL and lpdwBufferLength set to 0. The call fails with WSAENOBUFS, but lpdwBufferLength then contains the correct size of the buffer required to return all the protocol information. Once you allocate the correct buffer size and make another call with the supplied buffer, the function returns the number of WSAPROTOCOL_INFO structures returned. At this point, you can step through the structures to find the protocol entry with your required attributes. The sample program Enum.c on the companion CD-ROM enumerates all installed protocols and prints out the characteristics of each protocol.
The most commonly used field of the WSAPROTOCOL_INFO structure is dwServiceFlags1, which is a bit field for the various protocol attributes. Table 5-3 lists the various bit flags that can be set in the field and describes the meaning of each property. To check for the presence of a particular property, select the appropriate property flag and perform a bitwise AND of the property and the dwServiceFlags1 field. If the resultant value is nonzero, that property is present in the given protocol; otherwise, it isn't.
Table 5-3. Protocol flags
Property | Meaning |
---|---|
XP1_CONNECTIONLESS | This protocol provides connectionless service. If not set, the protocol supports connection-oriented data transfers. |
XP1_GUARANTEED_DELIVERY | This protocol guarantees that all data sent will reach the intended recipient. |
XP1_GUARANTEED_ORDER | This protocol guarantees that the data will arrive in the order in which it was sent and that it will not be duplicated. However, this does not guarantee delivery. |
XP1_MESSAGE_ORIENTED | This protocol honors message boundaries. |
XP1_PSEUDO_STREAM | This protocol is message-oriented, but the message boundaries are ignored on the receiver side. |
XP1_GRACEFUL_CLOSE | This protocol supports two-phase closes: each party is notified of the other's intent to close the communication channel. If not set, only abortive closes are performed. |
XP1_EXPEDITED_DATA | This protocol supports urgent data (out-of-band data). |
XP1_CONNECT_DATA | This protocol supports transferring data with the connection request. |
XP1_DISCONNECT_DATA | This protocol supports transferring data with the disconnect request. |
XP1_SUPPORT_BROADCAST | This protocol supports the broadcast mechanism. |
XP1_SUPPORT_MULTIPOINT | This protocol supports multipoint or multicast mechanisms. |
XP1_MULTIPOINT_CONTROL_PLANE | If this flag is set, the control plane is rooted. Otherwise, it is nonrooted. |
XP1_MULTIPOINT_DATA_PLANE | If this flag is set, the data plane is rooted. Otherwise, it is nonrooted. |
XP1_QOS_SUPPORTED | This protocol supports QOS requests. |
XP1_UNI_SEND | This protocol is unidirectional in the send direction. |
XP1_UNI_RECV | This protocol is unidirectional in the receive direction. |
XP1_IFS_HANDLES | The socket descriptors returned by the provider are Installable File System (IFS) handles and can be used in API functions such as ReadFile and WriteFile. |
XP1_PARTIAL_MESSAGE | The MSG_PARTIAL flag is supported in WSASend and WSASendTo. |
Most of these flags will be discussed in one or more of the following chapters, so we won't go into detail about the full meaning of each flag now. The other fields of importance are iProtocol, iSocketType, and iAddressFamily. The iProtocol field defines which protocol this entry belongs to. The iSocketType field is important if the protocol is capable of multiple behaviors, such as stream-oriented connections or datagram connections. Finally, iAddressFamily is used to distinguish the correct addressing structure to use for the given protocol. These three entries are of great importance when creating a socket for a given protocol and will be discussed in detail in the next section.