Partager via


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