Annotated Client Code with Checkv4 Output (Windows Embedded CE 6.0)
1/6/2010
The Checkv4 utility can help you find code that is sensitive to using in a version-independent scenario. Checkv4 provides enough information to get you started on changing your code.
You can obtain the Checkv4 utility from the IPv6 Technology Preview, available for download from this Microsoft Web site.
These examples show the Checkv4 output for the client code that you created in How to Convert an Application from IPv4 to IPv4/IPv6, and annotated code that describes the changes that you must make for the application to support both IPv4 and IPv6.
The following commenting conventions are used in the code example.
Commenting convention | Description |
---|---|
//checkv4 comment: <comment> |
Code included in the checkv4 output |
// Begin changes not included in the checkv4 output: <change needed> <code> //End changes. |
Code to be changed |
The following shows the Checkv4.exe output for the client code:
client.cpp(46) : sockaddr_in : use sockaddr_storage instead, or use sockaddr_in6 in addition for IPv6 support
client.cpp(50) : hostent : use addrinfo instead
client.cpp(85) : inet_addr : use WSAStringToAddress or getaddrinfo with AI_NUMERICHOST instead
client.cpp(88) : gethostbyname : use getaddrinfo instead
client.cpp(100) : AF_INET : use AF_INET6 in addition for IPv6 support
client.cpp(108) : AF_INET : use AF_INET6 in addition for IPv6 support
client.cpp(137) : AF_INET : use AF_INET6 in addition for IPv6 support
client.cpp(137) : gethostbyaddr : use getnameinfo instead
client.cpp(146) : in_addr : use in6_addr in addition for IPv6 support
client.cpp(146) : inet_ntoa : use WSAAddressToString or getnameinfo with NI_NUMERICHOST instead
client.cpp(192) : AF_INET : use AF_INET6 in addition for IPv6 support
client.cpp(192) : gethostbyaddr : use getnameinfo instead
client.cpp(201) : in_addr : use in6_addr in addition for IPv6 support
client.cpp(201) : inet_ntoa : use WSAAddressToString or getnameinfo with NI_NUMERICHOST instead
Annotated IPv4-only source code
The following IPv4-Only client source code example shows code that is annotated with changes you should make to fully support IPv4 and IPv6:
// Begin changes not included in the checkv4 output: Add winsock2.h and ws2tcpip.h to get access to IP version agnostic Winsock function calls and data structures
#include <winsock.h>
#include <windows.h>
#include <tchar.h>
#include <strsafe.h.>
// End changes
char pBuf[] = "WinCE Echo Test Packet";
#define DEFAULT_FAMILY AF_UNSPEC
#define DEFAULT_SOCKTYPE SOCK_STREAM
// Begin changes not included in the checkv4 output: Change port numbers to string format
#define DEFAULT_PORT 1234
//End changes
#define BUFFER_SIZE 23 // length of "WinCE Echo Test Packet"
#define TIMEOUT_SECS 2
#define TIMEOUT_USECS 0
#define RAS_SIZE 128
#define MIN(a,b) ((a) <= (b)) ? (a) : (b)
void
Print(
TCHAR *pFormat,
...)
{
va_list ArgList;
TCHAR Buffer[256];
va_start (ArgList, pFormat);
(void)StringCchVPrintf(Buffer, 256, pFormat, ArgList);
#ifndef UNDER_CE
_putts(Buffer);
#else
OutputDebugString(Buffer);
#endif
va_end(ArgList);
}
int _tmain (int argc, TCHAR* argv[])
{
SOCKET sock = INVALID_SOCKET;
int nSockType = DEFAULT_SOCKTYPE;
char szRemoteName[64];
// Begin changes not included in the checkv4 output: Change type of sPort to char*
short sPort = DEFAULT_PORT;
// End changes
// Begin changes not included in the checkv4 output: see checkv4 comments below..
sockaddr_in saRemoteAddr;
//End changes
//checkv4 comment: client.cpp(46) : sockaddr_in : use sockaddr_storage instead, or use sockaddr_in6 in addition for IPv6 support
int cbXfer, cbTotalRecvd, cbRemoteAddrSize;
WSADATA wsaData;
// Begin changes not included in the checkv4 output: Remove any DWORDs that hold IP addresses, IPv6 addresses are longer than sizeof(DWORD)
DWORD dwIPAddr;
struct hostent* h;
//End changes.
//checkv4 comment: client.cpp(50) : hostent : use addrinfo instead
char szRemoteAddrString[RAS_SIZE];
fd_set fdReadSet;
TIMEVAL timeout = {TIMEOUT_SECS, TIMEOUT_USECS};
char pRecvBuf[BUFFER_SIZE];
Print(TEXT("** Simple IPv4 Client **"));
// Begin changes not included in the checkv4 output: Change to MAKEWORD(2,2) so Winsock2.2 is used
if(WSAStartup(MAKEWORD(1,1), &wsaData))
//End changes.
{
// WSAStartup failed
return 1;
}
if(argc < 2)
{
Print(TEXT("Server name/address parameter required"));
goto Cleanup;
}
else
{
// we use the first argument as the server name/address
#if defined UNICODE
wcstombs(szRemoteName, argv[1], sizeof(szRemoteName));
#else
strncpy(szRemoteName, argv[1], sizeof(szRemoteName));
#endif
szRemoteName[63] = _T('\0');
Print(TEXT("Communicating with server - %hs\r\n"), szRemoteName);
}
//
// Resolve the server name/address
//
// Begin changes not included in the checkv4 output: see checkv4 comments below..
if ((dwIPAddr = inet_addr(szRemoteName)) == INADDR_NONE)
{
// remote server is not a dotted decimal IP address
h = gethostbyname(szRemoteName);
if(h != NULL)
{
memcpy(&dwIPAddr, h->h_addr_list[0], sizeof(dwIPAddr) );
}
else
{
Print (TEXT("ERROR: Invalid name/address parameter = %hs"), szRemoteName);
goto Cleanup;
}
}
//End changes
//checkv4 comment:client.cpp(85) : inet_addr : use WSAStringToAddress or getaddrinfo with AI_NUMERICHOST instead
//checkv4 comment:client.cpp(88) : gethostbyname : use getaddrinfo instead
// Begin changes not included in the checkv4 output: see Checkv4 comments below..
sock = socket(AF_INET, nSockType, 0);
if(sock == INVALID_SOCKET)
{
Print(TEXT("ERROR: socket() failed with error %d"), WSAGetLastError());
goto Cleanup;
}
saRemoteAddr.sin_family = AF_INET;
saRemoteAddr.sin_addr.s_addr = dwIPAddr;
saRemoteAddr.sin_port = htons(sPort);
//End changes.
client.cpp(100) : AF_INET : use AF_INET6 in addition for IPv6 support
client.cpp(108) : AF_INET : use AF_INET6 in addition for IPv6 support
// Begin changes not included in the checkv4 output: Make the socket and connect calls on each address returned by getaddrinfo until we find one to which we successfully connect to
if(nSockType == SOCK_STREAM)
{
// connect
if(connect(sock, (sockaddr *)&saRemoteAddr, sizeof(saRemoteAddr)) == SOCKET_ERROR)
{
Print(TEXT("ERROR: connect() failed with error %d"), WSAGetLastError());
goto Cleanup;
}
else
Print(TEXT("connect()'d successfully to 0x%08x"), dwIPAddr);
}
// End changes.
//
// Send data to the server
//
cbXfer = 0;
cbXfer = sendto(sock, pBuf, sizeof(pBuf), 0, (sockaddr *)&saRemoteAddr, sizeof(saRemoteAddr));
if(cbXfer != sizeof(pBuf))
{
Print(TEXT("ERROR: Couldn't send the data! error = %d\r\n"), WSAGetLastError());
goto Cleanup;
}
// Begin changes not included in the checkv4 output: see checkv4 comments below..
h = gethostbyaddr((char *)&dwIPAddr, sizeof(dwIPAddr), AF_INET);
if(h != NULL)
{
memcpy(szRemoteAddrString, h->h_name, MIN(strlen(h->h_name)+1, RAS_SIZE-1));
szRemoteAddrString[RAS_SIZE-1] = _T('\0');
}
else
{
Print (TEXT("Warning: Cannot obtain name for address 0x%08x"), dwIPAddr);
strcpy(szRemoteAddrString, inet_ntoa(*((in_addr*)&dwIPAddr)));
}
//End changes.
//checkv4 comment: client.cpp(137) : AF_INET : use AF_INET6 in addition for IPv6 support
//checkv4 comment: client.cpp(137) : gethostbyaddr : use getnameinfo instead
//checkv4 comment: client.cpp(146) : in_addr : use in6_addr in addition for IPv6 support
//checkv4 comment: client.cpp(146) : inet_ntoa : use WSAAddressToString or getnameinfo with NI_NUMERICHOST instead
Print(TEXT("SUCCESS: Sent %d bytes to server %hs\r\n"), cbXfer, szRemoteAddrString);
//
// Receive the echo'd data back from the server
//
FD_ZERO(&fdReadSet);
FD_SET(sock, &fdReadSet);
if(select(0, &fdReadSet, NULL, NULL, &timeout) != 1)
{
Print(TEXT("ERROR: Server hasn't responded in %d milliseconds\r\n"),
((timeout.tv_sec * 1000) + (timeout.tv_sec / 1000)));
goto Cleanup;
}
cbTotalRecvd = 0;
do
{
cbRemoteAddrSize = sizeof(saRemoteAddr);
cbXfer = recvfrom(sock, pRecvBuf + cbTotalRecvd, sizeof(pRecvBuf) - cbTotalRecvd, 0,
(sockaddr *)&saRemoteAddr, &cbRemoteAddrSize);
cbTotalRecvd += cbXfer;
} while(cbXfer > 0 && cbTotalRecvd < sizeof(pRecvBuf));
if(cbXfer == SOCKET_ERROR)
{
Print(TEXT("ERROR: Couldn't receive the data! Error = %d\r\n"), WSAGetLastError());
goto Cleanup;
}
else if(cbTotalRecvd != sizeof(pRecvBuf))
{
Print(TEXT("ERROR: Server didn't send back all the expected data!\r\n"));
goto Cleanup;
}
if(nSockType == SOCK_STREAM)
{
memset(&saRemoteAddr, 0, sizeof(saRemoteAddr));
cbRemoteAddrSize = sizeof(saRemoteAddr);
getpeername(sock, (sockaddr *)&saRemoteAddr, &cbRemoteAddrSize);
}
// Begin changes not included in the checkv4 output: see checkv4 comments below..
h = gethostbyaddr((char *)&(saRemoteAddr.sin_addr.s_addr), sizeof(saRemoteAddr.sin_addr.s_addr), AF_INET);
if(h != NULL)
{
memcpy(szRemoteAddrString, h->h_name, MIN(strlen(h->h_name)+1, RAS_SIZE-1));
szRemoteAddrString[RAS_SIZE-1] = _T('\0');
}
else
{
Print (TEXT("Warning: Cannot obtain name for address 0x%08x"), saRemoteAddr.sin_addr.s_addr);
strcpy(szRemoteAddrString, inet_ntoa(*((in_addr*)&(saRemoteAddr.sin_addr.s_addr))));
}
// End changes.
//checkv4 comment: client.cpp(192) : AF_INET : use AF_INET6 in addition for IPv6 support
//checkv4 comment: client.cpp(192) : gethostbyaddr : use getnameinfo instead
//checkv4 comment: client.cpp(201) : in_addr : use in6_addr in addition for IPv6 support
//checkv4 comment: client.cpp(201) : inet_ntoa : use WSAAddressToString or getnameinfo with NI_NUMERICHOST instead
Print(TEXT("SUCCESS - Received %d bytes back from server %hs\r\n"), cbTotalRecvd, szRemoteAddrString);
Cleanup:
if(sock != INVALID_SOCKET)
{
shutdown(sock, 2);
closesocket(sock);
}
WSACleanup();
Print(TEXT("** Simple IPv4 Client, Exiting **"));
return 0;
}
See Also
Tasks
Changing the Application Source Code to Support IPv6
How to Convert an Application from IPv4 to IPv4/IPv6