< Winsock 2 Protocols | Winsock2 Main | Chap 3: Winsock 2 & Internet Protocols >
What do we have in this crappy chapter 2 part 2?
|
The Winsock Catalog Program Example
1. While in the Visual C++ IDE, click File menu > Project sub menu to create a new project. 2. Select Win32 for the Project types: and Win32 Console Application for the Templates:. Put the project and solution name. Adjust the project location if needed and click OK. 3. Click Next for the Win32 Application Wizard Overview page. We will remove all the unnecessary project items. 4. In the Application page, select Empty project for the Additional options:. Leave others as given and click Finish.
|
5. Next, we need to add new source file. Click Project menu > Add New Item sub menu or select the project folder in the Solution Explorer > Select Add menu > Select New Item sub menu.
6. Select C++ File (.cpp) for the Templates:. Put the source file name and click Add. Although the extension is .cpp, Visual C++ IDE will recognize that the source code used is C based on the Compile as C Code (/TC) option which will be set in the project property page later.
7. Then, add the source code as given below.
// link with the Ws2_32.lib
#include <winsock2.h>
// link with the Rpcrt4.lib
#include <rpc.h>
#include <stdio.h>
// Print out the contents of a WSAPROTOCOL_INFO structure in
// a readable format.
static void PrintBufContent(WSAPROTOCOL_INFO *pProtocolBuf)
{
unsigned char *pszUuid;
int i;
printf(\nProtocol <%s>\n, pProtocolBuf->szProtocol);
// A guid is the same as a uuid.
UuidToString(&pProtocolBuf->ProviderId, (RPC_WSTR *)&pszUuid);
printf( ProviderId {%s}\n, pszUuid);
RpcStringFree((RPC_WSTR *)&pszUuid);
if (!pProtocolBuf->dwServiceFlags1)
printf( dwServiceFlags1: 0\n);
else
printf( dwServiceFlags1: 0x%08X\n,pProtocolBuf->dwServiceFlags1);
// Check which bit flags are set.
printf(\nChecking the set bit flags...\n);
if (pProtocolBuf->dwServiceFlags1 & XP1_CONNECTIONLESS)
printf( XP1_CONNECTIONLESS\n);
if (pProtocolBuf->dwServiceFlags1 & XP1_GUARANTEED_DELIVERY)
printf( XP1_GUARANTEED_DELIVERY\n);
if (pProtocolBuf->dwServiceFlags1 & XP1_GUARANTEED_ORDER)
printf( XP1_GUARANTEED_ORDER\n);
if (pProtocolBuf->dwServiceFlags1 & XP1_MESSAGE_ORIENTED)
printf( XP1_MESSAGE_ORIENTED\n);
if (pProtocolBuf->dwServiceFlags1 & XP1_PSEUDO_STREAM)
printf( XP1_PSEUDO_STREAM\n);
if (pProtocolBuf->dwServiceFlags1 & XP1_GRACEFUL_CLOSE)
printf( XP1_GRACEFUL_CLOSE\n);
if (pProtocolBuf->dwServiceFlags1 & XP1_EXPEDITED_DATA)
printf( XP1_EXPEDITED_DATA\n);
if (pProtocolBuf->dwServiceFlags1 & XP1_CONNECT_DATA)
printf( XP1_CONNECT_DATA\n);
if (pProtocolBuf->dwServiceFlags1 & XP1_DISCONNECT_DATA)
printf( XP1_DISCONNECT_DATA\n);
if (pProtocolBuf->dwServiceFlags1 & XP1_SUPPORT_BROADCAST)
printf( XP1_SUPPORT_BROADCAST\n);
if (pProtocolBuf->dwServiceFlags1 & XP1_SUPPORT_MULTIPOINT)
printf( XP1_SUPPORT_MULTIPOINT\n);
if (pProtocolBuf->dwServiceFlags1 & XP1_MULTIPOINT_CONTROL_PLANE)
printf( XP1_MULTIPOINT_CONTROL_PLANE\n);
if (pProtocolBuf->dwServiceFlags1 & XP1_MULTIPOINT_DATA_PLANE)
printf( XP1_MULTIPOINT_DATA_PLANE\n);
if (pProtocolBuf->dwServiceFlags1 & XP1_QOS_SUPPORTED)
printf( XP1_QOS_SUPPORTED\n);
if (pProtocolBuf->dwServiceFlags1 & XP1_INTERRUPT)
printf( XP1_INTERRUPT\n);
if (pProtocolBuf->dwServiceFlags1 & XP1_UNI_SEND)
printf( XP1_UNI_SEND\n);
if (pProtocolBuf->dwServiceFlags1 & XP1_UNI_RECV)
printf( XP1_UNI_RECV\n);
if (pProtocolBuf->dwServiceFlags1 & XP1_IFS_HANDLES)
printf( XP1_IFS_HANDLES\n);
if (pProtocolBuf->dwServiceFlags1 & XP1_PARTIAL_MESSAGE)
printf( XP1_PARTIAL_MESSAGE\n);
printf( dwServiceFlags2: reserved\n);
printf( dwServiceFlags3: reserved\n);
printf( dwServiceFlags4: reserved\n);
printf(\nChecking the Provider flags...\n);
printf( dwProviderFlags:\n);
if (pProtocolBuf->dwProviderFlags & PFL_MULTIPLE_PROTO_ENTRIES)
printf( PFL_MULTIPLE_PROTO_ENTRIES\n);
if (pProtocolBuf->dwProviderFlags & PFL_RECOMMENDED_PROTO_ENTRY)
printf( PFL_RECOMMENDED_PROTO_ENTRY\n);
if (pProtocolBuf->dwProviderFlags & PFL_HIDDEN)
printf( PFL_HIDDEN\n);
if (pProtocolBuf->dwProviderFlags & PFL_MATCHES_PROTOCOL_ZERO)
printf( PFL_MATCHES_PROTOCOL_ZERO\n);
printf(\nMore digging...\n);
printf( dwCatalogEntryId = %u\n, pProtocolBuf->dwCatalogEntryId);
printf( ProtocolChain.ChainLen = %d , pProtocolBuf->ProtocolChain.ChainLen);
if (pProtocolBuf->ProtocolChain.ChainLen == 1)
printf( (This is a base service provider)\n);
else if (pProtocolBuf->ProtocolChain.ChainLen > 1)
{
printf( (ProtocolChain layered to base protocol)\n);
for (i=0; i<pProtocolBuf->ProtocolChain.ChainLen; i++)
{
printf( Chain Catalog Entry Id = %u\n, pProtocolBuf->ProtocolChain.ChainEntries[i]);
}
}
else if (pProtocolBuf->ProtocolChain.ChainLen == 0)
printf( (This is a layered service provider)\n);
else
printf( Invalid\n);
printf( iVersion = %d\n, pProtocolBuf->iVersion);
printf( iAddressFamily = %d\n, pProtocolBuf->iAddressFamily);
printf( iMaxSockAddr = %d\n, pProtocolBuf->iMaxSockAddr);
printf( iMinSockAddr = %d\n, pProtocolBuf->iMinSockAddr);
// iProtocols returns a negative number for Microsoft NetBIOS
// service providers corresponding to the lana number * -1 (for
// example, -2 implies lana 2), except for lana 0 which is equal to
// 0x80000000 because protocol 0 is reserved for special use.
printf( iProtocol = %d\n, pProtocolBuf->iProtocol);
printf( iProtocolMaxOffset = %d\n, pProtocolBuf->iProtocolMaxOffset);
printf( iNetworkByteOrder = %s\n, ((pProtocolBuf->iNetworkByteOrder == LITTLEENDIAN) ?
LittleEndian : BigEndian));
printf( iSecurityScheme = %d\n, pProtocolBuf->iSecurityScheme);
printf( dwMessageSize = %u\n, pProtocolBuf->dwMessageSize);
printf( dwProviderReserved = reserved\n);
return;
}
int main(int argc, char *argv[])
{
WSADATA WSAData;
int i, nRet;
DWORD dwErr;
WSAPROTOCOL_INFO *lpProtocolBuf = NULL;
DWORD dwBufLen = 0;
// The WSAStartup() function directly returns the extended error code
// in the return value for this function. A call to the WSAGetLastError
// function is not needed and should not be used
if (WSAStartup(MAKEWORD(2,2), &WSAData) != 0)
printf(WSAStartup() error with code %d\n, WSAGetLastError());
else
{
printf(WSAStartup() is OK!\n);
// First, have WSAEnumProtocols tell you how big a buffer you need.
nRet = WSAEnumProtocols(NULL, lpProtocolBuf, &dwBufLen);
if (nRet != SOCKET_ERROR)
printf(WSAEnumProtocols() looks OK!\n);
else if ((dwErr = WSAGetLastError()) != WSAENOBUFS)
// WSAEnumProtocols() failed for some reason not relating to buffer size
printf(WSAEnumProtocols() failed with code %d\n, WSAGetLastError());
else
{
// WSAEnumProtocols failed for the expected reason.
// Now you need to allocate a buffer that is the right size.
lpProtocolBuf = (WSAPROTOCOL_INFO *)malloc(dwBufLen);
if (lpProtocolBuf)
{
// Now you can call WSAEnumProtocols again with the
// expectation that it will succeed
// because you have allocated a big enough buffer.
nRet = WSAEnumProtocols(NULL, lpProtocolBuf, &dwBufLen);
if (nRet == SOCKET_ERROR)
printf(WSAEnumProtocols() failed with code %d\n, WSAGetLastError());
else
{
// Enumerate the protocols.
printf(Enumerating the protocols...);
for (i=0; i<nRet; i++)
{
PrintBufContent(&lpProtocolBuf[i]);
printf(\nPress <Enter> for more info, if any...\n);
_fgetchar();
}
}
// Free up the allocated resource
free(lpProtocolBuf);
}
}
}
if(WSACleanup() != 0)
printf(WSACleanup() failed!...\n);
else
printf(WSACleanup() is OK...\n);
return 0;
}
8. Before we can build this Winsock C Win32 console application project, we need to set the project to be compiled as C code and link to ws2_32.lib and rpcrt4.lib. Invoke the project property page.
9. Expand the Configuration folder > Expand the C/C++ sub folder. Select the Advanced link and for the Compile As option, select Compile as C Code (/TC).
10. Next, expand the Linker folder and select the Input link. For the Additional Dependencies option, you can just directly type the library name in the empty field on the right of the Additional Dependencies separated by a space and click OK.
Or click the ellipses at the end of the empty field on the right side. Manually, type the library name separated by a newline and click OK.
11. Build the project and make sure there is no error which can be seen (if any) in the Output window normally docked at the bottom of the IDE by default. Run the project. If there is no error, a sample output is shown below.
-------------------------------------------------
On 64-bit Windows, it is possible to run 32-bit applications under the WOW64 (Windows on Windows) subsystem. Because both 32-bit and 64-bit applications may need to access the Winsock catalog, the system maintains two separate catalogs. When a 64-bit Winsock application runs and calls WSAEnumProtocols, the 64-bit catalog is used. Likewise, when a 32-bit Winsock application calls WSAEnumProtocols, the 32-bit catalog is used. This will become more important when dealing with the Winsock Service Provider Interface (WSP*).
In Chapter 1 we saw simple examples of how to create a socket using the socket() function. This function takes three parameters: address family, socket type, and protocol. When an application creates a socket, the Winsock catalog is consulted and an attempt is made to match the supplied parameters with those contained in each WSAPROTOCOL_INFO structure. If the parameters match, then a socket is created from that provider. Note that in some instances the protocol parameter can be 0. If the dwProviderFlags field of the WSAPROTOCOL_INFO structure is PFL_MATCHES_PROTOCOL_ZERO and if the requested address family and socket type match its entries, then that provider is used to create a socket. For example, consider the following call:
SOCKET s;
s = socket(AF_INET, SOCK_STREAM, 0);
Winsock will enumerate the catalog and first match the address family followed by the socket type. Since the protocol value is 0 and the MSAFD TCP provider contains the PFL_MATCHES_PROTOCOL_ZERO flag, this call will create a TCP socket from the MSAFD TCP provider. The system will not attempt to match the request to any further providers.
In some instances, multiple providers may share the same address family, socket type, and protocol. This is the case with the RSVP provider. The RSVP provider offers QOS over TCP/IP and UDP/IP (Take note that MSDN said RSVP signaling is not supported on Windows XP, Windows Server 2003, or later versions of Windows.) Because multiple providers share the same address family, socket type, and protocol, there is no way to use the socket() API to create a socket from the RSVP provider. To do so, you must use the Winsock 2 function WSASocket(), which is defined as:
SOCKET WSASocket(
int af,
int type,
int protocol,
LPWSAPROTOCOL_INFO lpProtocolInfo,
GROUP g,
DWORD dwFlags);
The first three parameters are the same as those of socket but the fourth parameter takes a WSAPROTOCOL_INFO structure. If lpProtocolInfo references a provider entry and each of the first three parameters is the predefined value FROM_PROTOCOL_INFO, then a socket is created from the given provider. An application can create an RSVP socket using this method.
The fifth parameter deals with socket groups that are discussed in the Winsock specification but are not implemented in Windows. The last parameter is optional flags that may be passed. For now, the only flag of importance is WSA_FLAG_OVERLAPPED. If you plan on using overlapped IO, then this flag needs to be present when creating the socket. Note that when using the socket API, the overlapped flag is always implied. The other socket flags pertain to multicasting.
1. While in the Visual C++ IDE, click File menu > Project sub menu to create a new project.
2. Select Win32 for the Project types: and Win32 Console Application for the Templates:. Put the project and solution name. Adjust the project location if needed and click OK.
3. Click Next for the Win32 Application Wizard Overview page. We will remove all the unnecessary project items.
4. In the Application page, select Empty project for the Additional options:. Leave others as given and click Finish.
5. Next, we need to add new source file. Click Project menu > Add New Item sub menu or select the project folder in the Solution Explorer > Select Add menu > Select New Item sub menu.
6. Select C++ File (.cpp) for the Templates:. Put the source file name and click Add. Although the extension is .cpp, Visual C++ IDE will recognize that the source code used is C based on the Compile as C Code (/TC) option which will be set in the project property page later.
7. Next, add the source code as given below.
#include <winsock2.h>
#include <stdio.h>
int main(int argc, char **argv)
{
WSADATA WSAData;
int i, nRet;
WSAPROTOCOL_INFO *lpProtocolBuf = NULL;
DWORD dwBufLen = 0;
SOCKET SocDescriptor;
DWORD dwErr;
BOOL bProtocolFound;
if (WSAStartup(MAKEWORD(2,2), &WSAData) != 0)
printf(WSAStartup() failed with error code %ld\n, WSAGetLastError());
else
{
printf(WSAStartup() seems OK!\n);
// First, have WSAEnumProtocols() tell you how big a buffer you need
nRet = WSAEnumProtocols(NULL, lpProtocolBuf, &dwBufLen);
printf(The buffer size is %d bytes...\n, dwBufLen);
// If failed, returns SOCKET_ERROR
if (nRet != SOCKET_ERROR)
printf(WSAEnumProtocols() does not return SOCKET_ERROR!\n);
// WSAENOBUFS - The buffer length was too small
else if ((dwErr = WSAGetLastError()) != WSAENOBUFS)
// WSAEnumProtocols() failed for some reason not relating to buffer size
printf(WSAEnumProtocols() does not return WSAENOBUFS,\n
however failed with error code %ld\n, WSAGetLastError());
else
{
// WSAEnumProtocols() failed for the expected reason. Therefore,
// you need to allocate a buffer of the appropriate size.
printf(Allocating the buffer of the appropriate size...\n);
lpProtocolBuf = (WSAPROTOCOL_INFO *)malloc(dwBufLen);
printf(Recheck, the buffer size is %d bytes...\n, dwBufLen);
if (lpProtocolBuf)
{
// Now you can call WSAEnumProtocols() again with the expectation
// that it will succeed because you have allocated a big enough buffer.
nRet = WSAEnumProtocols(NULL, lpProtocolBuf, &dwBufLen);
if (nRet == SOCKET_ERROR)
printf(WSAEnumProtocols() failed with error code %d\n, WSAGetLastError());
else
{
printf(WSAEnumProtocols() looks pretty fine!\n);
// Loop through protocols, looking for the first service
// provider that meets the matching criteria.
// Originally FALSE, if found change to TRUE
printf(Matching the specified service provider...\n);
printf( IPPROTO_TCP and XP1_QOS_SUPPORTED...\n);
bProtocolFound = FALSE;
for (i=0; i<nRet; i++)
{
if ((lpProtocolBuf[i].iProtocol == IPPROTO_TCP) &&
((XP1_QOS_SUPPORTED & lpProtocolBuf[i].dwServiceFlags1) ==
XP1_QOS_SUPPORTED))
{
bProtocolFound = TRUE;
// first service provider matched, exit the loop
break;
}
}
printf(The specified service provider found/matched! buffer index, i is
%d...\n, i);
// Once you have chosen a service provider, the following sample code
// demonstrates how to actually create a socket using a supplied
// WSAPROTOCOL_INFO structure
// from the service provider you have chosen
SocDescriptor = WSASocket(
FROM_PROTOCOL_INFO, // manifest constant
FROM_PROTOCOL_INFO, // manifest constant
FROM_PROTOCOL_INFO, // manifest constant
&lpProtocolBuf[i], // from WSAPROTOCOL_INFO
0, // reserved
WSA_FLAG_OVERLAPPED);
printf(Reconfirm the buffer index, i is %d\n, i);
if (SocDescriptor == INVALID_SOCKET)
{
printf(WSASocket() failed with error code %d\n, WSAGetLastError());
WSACleanup();
}
else
printf(WSASocket() looks fine, continue on next tasks!\n);
}
}
}
}
// If not needed anymore, deallocate memory to the system's heap
free(lpProtocolBuf);
// WSA cleanup
if(WSACleanup() != 0)
printf(WSACleanup() failed!...\n);
else
printf(WSACleanup() is OK...\n);
return 0;
}
8. Before we can build this Winsock C Win32 console application project, we need to set the project to be compiled as C code and link to ws2_32.lib, the Winsock2 library. Invoke the project property page.
9. Expand the Configuration folder > Expand the C/C++ sub folder. Select the Advanced link and for the Compile As option, select Compile as C Code (/TC).
10. Next, expand the Linker folder and select the Input link. For the Additional Dependencies option, click the ellipses at the end of the empty field on the right side. Manually, type the library name, ws2_32.lib and click OK. Or you can just directly type the library name in the empty field on the right of the Additional Dependencies. Click OK.
11. Build the project and make sure there is no error which can be seen (if any) in the Output window normally docked at the bottom of the IDE by default.
12. Run the project. If there is no error, a sample output is shown below.
< Winsock 2 Protocols | Winsock2 Main | Chap 3: Winsock 2 & Internet Protocols >