Ping

The Ping provides the ability to programatically ping network components using the ICMP ping protocol. This is exactly the same ping that you use from the command line.

You can ping all of the components necessary for a distributed control system to validate that it can operate correctly or you can continuously ping a single component to maintain its status.

Ping.h

/***************************************************************************************
* Copyright (c) 2006 - 2011 Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342 *
***************************************************************************************/

/*********************************************************************************************
*                                                                                            *
*  Ping.cpp is an extensive rewrite of Ping.c (Copyright 1996 - 1998 Microsoft Corporation). *
*                                                                                            *
*********************************************************************************************/

#ifndef _PING_H_
#define _PING_H_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000

#ifndef _WINSOCK2API_

//#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>

#endif   // _WINSOCK2API_

#ifdef TRACE_HEADERS
#pragma message ( "NOTE:  Included header file:  \"" __FILE__ "\"" )
#endif

#ifndef _INC_STDIO
#include <STDIO.H>
#endif   // _INC_STDIO

// Enumerated Error Codes

typedef enum tagErrorCodes {     // <WINERROR.H>

   VPE_SUCCESS,                  // No Error

   VPE_NOT_A_VALID_OBJECT,       // IsValid() Failed!

   VPE_WSA_STARTUP,              // WSAStartup() Call Failed - See m_nWSAStartupError for Specific Error
   VPE_WSA_BAD_SOCKET_VERSION,   // The WinSock Version is Unexceptable
   VPE_WSA_SOCKET,               // WSASocket() Call Failed - Use WSAGetLastError() for More Info
   VPE_WSA_SOCKET_OPT,           // setsockopt() Call Failed - Use WSAGetLastError() for More Info
   VPE_PACKET_ALLOC_FAILED,      // xmalloc() Call Failed to Allocate Packet
   VPE_BAD_ICMP_PACKET_SIZE,     // FillICMPSendData() Called with an Illegal Packet Size
   VPE_BAD_ICMP_ECHO_DATA,       // DecodeICMPPingEcho() - Couldn't Decode All Buffer Addresses
   VPE_BAD_ICMP_ECHO_SIZE,       // DecodeICMPPingEcho() - Found an Illegal Packet Size
   VPE_BAD_IP_HEADER_CHECKSUM,   // DecodeICMPPingEcho() - Bad IP Header CheckSum
   VPE_BAD_ICMP_PACKET_CHECKSUM, // DecodeICMPPingEcho() - Bad ICMP Packet CheckSum
   VPE_NOT_ICMP_ECHO_REPLY,      // DecodeICMPPingEcho() - The Packet was NOT an ICMP Echo Reply
   VPE_NOT_MY_ICMP_PACKET,       // DecodeICMPPingEcho() - The ICMP Packet was NOT mine
   VPE_BAD_ICMP_PACKET_SEQUENCE, // DecodeICMPPingEcho() - The ICMP Packet is Out of Sequence
   VPE_BAD_ICMP_PACKET_DATA,     // DecodeICMPPingEcho() - The ICMP Packet Data is Corrupt
   VPE_BAD_PING_ADDRESS,         // Ping() - The Name of the Computer to Ping was Unresolvable
   VPE_SEND_PING_TIMED_OUT,      // Ping() - Ping had a sendto() Timeout
   VPE_SEND_PING_FAILED,         // Ping() - Ping had a sendto() Failure
   VPE_SEND_PING_BYTE_COUNT,     // Ping() - Ping had a sendto() Write Underflow/Overflow
   VPE_RECV_ECHO_TIMED_OUT,      // Ping() - Ping had a recvfrom() Timeout
   VPE_RECV_ECHO_FAILED,         // Ping() - Ping had a recvfrom() Failure

   VPE_UNKNOWN_ERROR,            // Unable to Determine the Error Condition

   VPE_NUMBER_OF_ERROR_CODES     // This must be LAST!

} EPINGERROR, * LPEPINGERROR;

/////////////////////////////////////////////////////////////////////////////
// CPing Class

class

#ifdef _AFXEXT
AFX_EXT_CLASS
#endif

CPing

   {

   public:

   // Construction

      CPing ( DWORD dwRcvTimeout = 100LU, DWORD dwSndTimeout = 100LU );

      virtual ~CPing();

   // Attributes

   protected:

      bool                 m_fIsValid;          // Is the CPing Object Valid?

      volatile long        m_lnPingSpinLock;    // The Ping SpinLock

      EPINGERROR           m_eLastPingError;    // The Last Ping Error
      int                  m_nWSAStartupError;  // The Error Code Returned by WSAStartup()

      WSADATA              m_stWSAData;         // The Windows Sockets API Implementation Data
      SOCKET               m_sRawSocket;        // The Raw ICMP Socket used by Ping
      struct sockaddr_in   m_stDestAddr;        // The Network Address to be Ping'ed
      struct sockaddr_in   m_stFromAddr;        // The Network Address that Responded to the Ping
      struct hostent       * m_lpHostEntry;     // The Host Entry Structure returned by gethostbyname()
      DWORD                m_dwRcvTimeout;      // The Socket Recv Timeout in ms
      DWORD                m_dwSndTimeout;      // The Socket Send Timeout in ms

      char                 m_strDestTCPIPAddr [ MAX_COMPUTERNAME_LENGTH + 1 ];   // The Address of the Network Component being Ping'ed

      BYTE                 * m_lpabICMPData;    // The Address of the Outgoing Ping Packet
      size_t               m_cbabICMPData;      // The Size of the Outgoing Ping Packet
      BYTE                 * m_lpabICMPEcho;    // The Address of the Incoming Ping Echo
      size_t               m_cbabICMPEcho;      // The Size of the Incoming Ping Echo

      int                  m_nSequenceNumber;   // The Sequence Number of the ICMP Ping Packet

      FILE                 * m_hStdErr;         // The Standard Error  Handle (or NULL if Not Used)
      FILE                 * m_hStdOut;         // The Standard Output Handle (or NULL if Not Used)

   // Operations

   public:

   // Implementation

   protected:

      bool        FillICMPSendData     ( void );
      USHORT      CheckSum             ( VOID * lpvBuffer, size_t cbvBuffer );
      bool        DecodeICMPPingEcho   ( VOID * pvBuffer, size_t cbBuffer, struct sockaddr_in * stFromAddr, int nSequenceNumber );

      bool        SetSndTimeout        ( DWORD dwSndTimeout );
      bool        SetRcvTimeout        ( DWORD dwRcvTimeout );

   public:

      bool        IsValid              ( void );

      EPINGERROR  GetLastError         ( void );

      void        PrintNarative        ( FILE * hStdOut );
      void        PrintErrors          ( FILE * hStdErr );

      bool        GetTCPIPAddress      ( LPCSTR szComputerAddress, char * szTCPIPAddr, size_t cbTCPIPAddr );

      bool        Ping                 ( LPCSTR strComputerAddress, int nTimesPinged = 1, DWORD dwSleepPeriodBetweenPingsInms = 1000LU );

   };

#endif // #define _PING_H_

Ping.cpp

/***************************************************************************************
* Copyright (c) 2006 - 2011 Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342 *
***************************************************************************************/

/*********************************************************************************************
*                                                                                            *
*  Ping.cpp is an extensive rewrite of Ping.c (Copyright 1996 - 1998 Microsoft Corporation). *
*                                                                                            *
*  This code implements a spinlock critical section for the Ping() function.  This assures   *
*  that the socket is dedicated to a single ping.  Ping() is the only public function that   *
*  accesses the critical section, so protecting it should therefore make the class be tread  *
*  safe                                                                                      *
*                                                                                            *
*********************************************************************************************/

#define WIN32_LEAN_AND_MEAN            // Exclude rarely-used stuff from Windows headers

#define _WIN32_WINNT 0x0400            // Needed for SwitchToThread()

#include <WINDOWS.H>

#include "Ping.h"                      // The CPing Base Class, Prototypes and Defines

#pragma comment ( lib, "ws2_32.lib" )

#define ICMP_ECHO       8
#define ICMP_ECHOREPLY  0

#define ICMP_MIN        8              // Minimum 8 Byte ICMP Packet (Just the Header)

#pragma pack ( 4 )

// IP header

typedef struct tagIPHeader

   {

   unsigned int   h_len:4;             // Length of the Header in 32-Bit Words
   unsigned int   version:4;           // Version of IP
   unsigned char  tos;                 // Type of Service
   unsigned short total_len;           // Total Length of the Packet
   unsigned short ident;               // Unique Identifier
   unsigned short frag_and_flags;      // Flags
   unsigned char  ttl;                 // ?
   unsigned char  proto;               // Protocol (TCP, UDP etc)
   unsigned short checksum;            // IP Checksum

   unsigned int sourceIP;              // The Source TCP/IP Address
   unsigned int destIP;                // The Destination TCP/IP Address

   } IPHeader;

// ICMP header

typedef struct tagICMPHeader

   {

      BYTE     i_type;
      BYTE     i_code;                 /* type sub code */
      USHORT   i_cksum;
      USHORT   i_id;
      USHORT   i_seq;

   } ICMPHeader;

#define STATUS_FAILED   0xFFFF
#define DEF_PACKET_SIZE 32
#define MAX_PACKET      1024

#define xmalloc(s)   HeapAlloc   ( GetProcessHeap(), HEAP_ZERO_MEMORY, ( s ) )
#define xfree(p)     HeapFree    ( GetProcessHeap(), 0, ( p ) )

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#undef THIS_FILE
static char THIS_FILE[] = __FILE__;

/////////////////////////////////////////////////////////////////////////////
// CPing

static const WSADATA             WSADefData  = { 0U };
static const struct sockaddr_in  stDefAddr   = { AF_INET };

CPing::CPing ( DWORD dwRcvTimeout, DWORD dwSndTimeout ) :

   m_fIsValid           ( false        ), // Is the CPing Object Valid?

   m_lnPingSpinLock     ( 0            ), // The Ping SpinLock

   m_eLastPingError     ( VPE_SUCCESS  ), // The Last Ping Error

   m_nWSAStartupError   ( 0            ), // The Error Code Returned by WSAStartup()
   m_stWSAData          ( WSADefData   ), // The Windows Sockets API Implementation Data

   m_sRawSocket         ( 0U           ), // The Raw ICMP Socket used by Ping

   m_stDestAddr         ( stDefAddr    ), // The Network Address to be Ping'ed
   m_stFromAddr         ( stDefAddr    ), // The Network Address that Responded to the Ping

   m_lpHostEntry        ( NULL         ), // The Host Entry Structure returned by gethostbyname()

   m_dwRcvTimeout       ( dwRcvTimeout ), // The Socket Recv Timeout in ms
   m_dwSndTimeout       ( dwSndTimeout ), // The Socket Send Timeout in ms

   m_lpabICMPData       ( NULL         ), // The Address of the Outgoing Ping Packet
   m_cbabICMPData       ( 0U           ), // The Size of the Outgoing Ping Packet
   m_lpabICMPEcho       ( NULL         ), // The Address of the Incoming Ping Echo
   m_cbabICMPEcho       ( 0U           ), // The Size of the Incoming Ping Echo

   m_nSequenceNumber    ( 0            ), // The Sequence Number of the ICMP Ping Packet

   m_hStdErr            ( NULL         ), // The Standard Error  Handle (or NULL if Not Used)
   m_hStdOut            ( NULL         )  // The Standard Output Handle (or NULL if Not Used)

   {

   // Perform the Default Initialization

   memset ( m_strDestTCPIPAddr, 0, sizeof m_strDestTCPIPAddr );

   // Start Up Windows Sockets and Assure that it is Version 2.1 or Higher

   if ( ( m_nWSAStartupError = WSAStartup ( MAKEWORD ( 2, 1 ),&m_stWSAData ) ) != 0 )
      {
      m_eLastPingError = VPE_WSA_STARTUP;
      return;
      }

   // Get the Current Version of WinSocks (bHiVers.bLoVers - i.e. 2.2)

   BYTE bCVHiVers = LOBYTE ( m_stWSAData.wHighVersion );
   BYTE bCVLoVers = HIBYTE ( m_stWSAData.wHighVersion );

   // Get the Version ofWinSocks that the User Will Use (bHiVers.bLoVers - i.e. 2.2)

   BYTE bReqHiVers = LOBYTE ( m_stWSAData.wVersion );
   BYTE bReqLoVers = HIBYTE ( m_stWSAData.wVersion );

   // Assure that the Sockets Version is Acceptable

   if ( bReqHiVers > bCVHiVers )
      {
      m_eLastPingError = VPE_WSA_BAD_SOCKET_VERSION;
      return;
      }
   else if ( bReqHiVers == bCVHiVers && bReqLoVers > bCVLoVers)
      {
      m_eLastPingError = VPE_WSA_BAD_SOCKET_VERSION;
      return;
      }

   // Create an Internet Control Message Protocol (ICMP) Raw Socket

   m_sRawSocket = WSASocket ( AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, WSA_FLAG_OVERLAPPED );

   if ( m_sRawSocket == INVALID_SOCKET )
      {
      m_eLastPingError = VPE_WSA_SOCKET;
      return;
      }

   // Set the Send and Receive Timeout Values

   if ( setsockopt ( m_sRawSocket, SOL_SOCKET, SO_SNDTIMEO, ( char * ) &m_dwSndTimeout, sizeof ( m_dwSndTimeout ) ) == SOCKET_ERROR )
      {
      m_eLastPingError = VPE_WSA_SOCKET_OPT;
      return;
      }

   if ( setsockopt ( m_sRawSocket, SOL_SOCKET, SO_RCVTIMEO, ( char * ) &m_dwRcvTimeout, sizeof ( m_dwRcvTimeout ) ) == SOCKET_ERROR )
      {
      m_eLastPingError = VPE_WSA_SOCKET_OPT;
      return;
      }

   // Allocate the Packet Buffers

   if ( ( m_lpabICMPData = ( BYTE * ) xmalloc ( MAX_PACKET ) ) == NULL )
      {
      m_eLastPingError = VPE_PACKET_ALLOC_FAILED;
      return;
      }

   m_cbabICMPData = DEF_PACKET_SIZE + sizeof ( ICMPHeader ) + sizeof ( DWORD );

   if ( ( m_lpabICMPEcho = ( BYTE * ) xmalloc ( MAX_PACKET ) ) == NULL )
      {
      m_eLastPingError = VPE_PACKET_ALLOC_FAILED;
      return;
      }

   // Fill in the Send Packet Default Data

   if ( ! FillICMPSendData() ) return;

   // Set the CPing Object to Valid

   m_fIsValid = true;

   }  // CPing::CPing()

CPing::~CPing()

   {

   // Set the CPing Object Valid Flag to Invalid

   m_fIsValid = false;

   // Shutdown the Windows Sockets Application

   WSACleanup();

   // Free the Packet Buffers

   if ( m_lpabICMPData )
      {
      xfree ( m_lpabICMPData );
      m_lpabICMPData = NULL;
      m_cbabICMPData = 0;
      }

   if ( m_lpabICMPEcho )
      {
      xfree ( m_lpabICMPEcho );
      m_lpabICMPEcho = NULL;
      m_cbabICMPEcho = 0;
      }

   }  // CPing::~CPing()

bool CPing::IsValid ( void )

   {

   // Assure that "this" Points to a Valid Read/Write Address

   if ( IsBadWritePtr ( this, sizeof ( CPing ) ) ) return false;

   // Return the Value of the m_fIsValid Member

   return this->m_fIsValid;

   }  // CPing::IsValid ( void )

// Helper function to fill in various stuff in our ICMP request.

bool CPing::FillICMPSendData ( void )

   {
   ICMPHeader  * lpICMPHeader    = ( ICMPHeader * ) m_lpabICMPData;
   DWORD       * lpdwTickCount   = ( DWORD      * ) ( lpICMPHeader   + 1 );
   BYTE        * lpabPingBuffer  = ( BYTE       * ) ( lpdwTickCount  + 1 );

   int         cbabPingBuffer    = m_cbabICMPData - ( int ) sizeof ( ICMPHeader ) - ( int ) sizeof ( DWORD );

   // Initialize Error Status to Success

   m_eLastPingError = VPE_SUCCESS;

   // Error if Buffer is Too Large or Too Small

   if ( m_cbabICMPData > MAX_PACKET || cbabPingBuffer < 0 )
      {
      m_eLastPingError = VPE_BAD_ICMP_PACKET_SIZE;
      return false;
      }

   // Initialize the Buffer to All Zeros

   memset ( m_lpabICMPData, '\0', m_cbabICMPData );

   // Initialize the ICMP Header Information

   lpICMPHeader->i_type = ICMP_ECHO;
   lpICMPHeader->i_id   = ( USHORT ) GetCurrentProcessId();

   // Initialize the Data Buffer to All E's

   memset ( lpabPingBuffer,'E', cbabPingBuffer );

   return true;

   }  // bool CPing::FillICMPSendData ( void )

USHORT CPing::CheckSum ( VOID * lpvBuffer, size_t cbvBuffer )

   {
   USHORT   * usBuffer  = ( USHORT * ) lpvBuffer;
   DWORD    dwChkSum    = 0;

   while ( cbvBuffer > 1 )
      {
      dwChkSum += * usBuffer++;
      cbvBuffer -= sizeof ( USHORT );
      }

   if ( cbvBuffer )
      {
      dwChkSum += * ( UCHAR * ) usBuffer;
      }

   dwChkSum =  ( dwChkSum >> 16 ) + ( dwChkSum & 0xffff );
   dwChkSum += ( dwChkSum >> 16 );

   return ( USHORT ) ( ~ dwChkSum );

   }  // USHORT CPing::CheckSum ( VOID * lpvBuffer, size_t cbvBuffer )

bool CPing::DecodeICMPPingEcho ( VOID * pvBuffer, size_t cbBuffer, struct sockaddr_in * stFromAddr, int nSequenceNumber )

   {

   // Assure that the CPing Object is Valid

   if ( ! IsValid() ) return false;

   // Initialize Error Status to Success

   m_eLastPingError = VPE_SUCCESS;

   // The response is an IP packet.  We must decode the IP header to locate the ICMP data - Compute the Various Buffer Pointers and Sizes

   IPHeader    * lpIPHeader   = pvBuffer     ? ( IPHeader *       ) pvBuffer                                : NULL;
   size_t      cbIPHeader     = lpIPHeader   ? ( ( size_t         ) lpIPHeader->h_len * 4 )                 : 0;

   ICMPHeader  * lpICMPHeader = lpIPHeader   ? ( ICMPHeader *     ) ( ( size_t ) lpIPHeader + cbIPHeader )  : NULL;
   DWORD       * lpTickCount  = lpICMPHeader ? ( DWORD *          ) ( lpICMPHeader + 1 )                    : NULL;
   BYTE        * lpabICMPData = lpTickCount  ? ( BYTE *           ) ( lpTickCount + 1 )                     : NULL;

   size_t      cbabICMPData   = ( size_t ) pvBuffer + cbBuffer - ( size_t ) lpabICMPData;

   size_t      i              = 0;

   // Validate the Data Regions

   if ( ! lpIPHeader || ! lpICMPHeader || ! lpTickCount || ! lpabICMPData )
      {
      if ( m_hStdErr ) fprintf ( m_hStdErr, "Illegal packet buffer returned by %s\n\a", inet_ntoa ( stFromAddr->sin_addr ) );
      m_eLastPingError = VPE_BAD_ICMP_ECHO_DATA;
      return FALSE;
      }

   // Validate the Packet Size

   if ( cbBuffer < ( cbIPHeader + ICMP_MIN ) || cbBuffer > MAX_PACKET )
      {
      if ( m_hStdErr ) fprintf ( m_hStdErr, "Illegal packet size from %s\n\a", inet_ntoa ( stFromAddr->sin_addr ) );
      m_eLastPingError = VPE_BAD_ICMP_ECHO_SIZE;
      return FALSE;
      }

   // Validate the Check Sums

   if ( CheckSum ( lpIPHeader, cbIPHeader ) )
      {
      if ( m_hStdErr ) fprintf ( m_hStdErr, "IP Header checksum failure!\n" );
      m_eLastPingError = VPE_BAD_IP_HEADER_CHECKSUM;
      return  FALSE;
      }

   if ( CheckSum ( lpICMPHeader, sizeof ( ICMPHeader ) + sizeof ( DWORD ) + cbabICMPData ) )
      {
      if ( m_hStdErr ) fprintf ( m_hStdErr, "ICMP Packet checksum failure!\n\a" );
      m_eLastPingError = VPE_BAD_ICMP_PACKET_CHECKSUM;
      return  FALSE;
      }

   // Validate that Packet is an ICMP Echo Reply

   if ( lpICMPHeader->i_type != ICMP_ECHOREPLY )
      {
      if ( m_hStdErr ) fprintf ( m_hStdErr, "non-echo type %d recvd\n", lpICMPHeader->i_type );
      m_eLastPingError = VPE_NOT_ICMP_ECHO_REPLY;
      return FALSE;
      }

   // Assure that Packet is Mine

   if ( lpICMPHeader->i_id != ( USHORT ) GetCurrentProcessId() )
      {
      if ( m_hStdErr ) fprintf ( m_hStdErr, "someone else's packet!\n" );
      m_eLastPingError = VPE_NOT_MY_ICMP_PACKET;
      return  FALSE;
      }

   // Assure that it is the Correct Sequence Number

   if ( lpICMPHeader->i_seq != ( USHORT ) nSequenceNumber )
      {
      if ( m_hStdErr ) fprintf ( m_hStdErr, "Wrong sequence Number!\n\a" );
      m_eLastPingError = VPE_BAD_ICMP_PACKET_SEQUENCE;
      return  FALSE;
      }

   // Validate the Data

   for ( i = 0; i < cbabICMPData; i++ )
      {
      if ( lpabICMPData [ i ] != 'E' )
         {
         if ( m_hStdErr ) fprintf ( m_hStdErr, "Corrupt data buffer returned by %s\n\a", inet_ntoa ( stFromAddr->sin_addr ) );
         m_eLastPingError = VPE_BAD_ICMP_PACKET_DATA;
         return  FALSE;
         }
      }

   // Output the Packet Info

   if ( m_hStdOut )
      {
      fprintf ( m_hStdOut, "%d bytes from %s:", cbBuffer, inet_ntoa ( stFromAddr->sin_addr ) );
      fprintf ( m_hStdOut, " i_seq = %d ",      lpICMPHeader->i_seq );
      fprintf ( m_hStdOut, " time: %d ms ",     GetTickCount() - lpTickCount [ 0 ] );
      fprintf ( m_hStdOut, "\n" );
      }

   return TRUE;

   }  // bool CPing::DecodeICMPPingEcho ( VOID * pvBuffer, size_t cbBuffer, struct sockaddr_in * stFromAddr, int nSequenceNumber )

EPINGERROR CPing::GetLastError ( void )

   {

   // Assure that this is a Valid CPing Object

   if ( ! IsValid() )
      return VPE_NOT_A_VALID_OBJECT;
   else
      return m_eLastPingError;

   }  // EPINGERROR CPing::GetLastError ( void )

void CPing::PrintNarative ( FILE * hStdOut )

   {

   if ( IsValid() ) m_hStdOut = hStdOut;

   }  // void CPing::PrintNarative ( FILE * hStdOut )

void CPing::PrintErrors ( FILE * hStdErr )

   {

   if ( IsValid() ) m_hStdErr = hStdErr;

   }  // void CPing::PrintErrors ( FILE * hStdErr )

bool CPing::SetSndTimeout ( DWORD dwSndTimeout )

   {

   // Assure that the CPing Object is Valid

   if ( ! IsValid() ) return false;

   // Initialize Error Status to Success

   m_eLastPingError = VPE_SUCCESS;

   // Set the Send Timeout Value

   if ( setsockopt ( m_sRawSocket, SOL_SOCKET, SO_SNDTIMEO, ( char * ) &dwSndTimeout, sizeof ( dwSndTimeout ) ) == SOCKET_ERROR )
      {
      m_eLastPingError = VPE_WSA_SOCKET_OPT;
      return false;
      }

   m_dwSndTimeout = dwSndTimeout;

   return true;

   }  // bool CPing::SetSndTimeout ( DWORD dwSndTimeout )

bool CPing::SetRcvTimeout ( DWORD dwRcvTimeout )

   {

   // Assure that the CPing Object is Valid

   if ( ! IsValid() ) return false;

   // Initialize Error Status to Success

   m_eLastPingError = VPE_SUCCESS;

   // Set the Send Timeout Value

   if ( setsockopt ( m_sRawSocket, SOL_SOCKET, SO_RCVTIMEO, ( char * ) &dwRcvTimeout, sizeof ( dwRcvTimeout ) ) == SOCKET_ERROR )
      {
      m_eLastPingError = VPE_WSA_SOCKET_OPT;
      return false;
      }

   m_dwRcvTimeout = dwRcvTimeout;

   return true;

   }  // bool CPing::SetRcvTimeout ( DWORD dwRcvTimeout )

bool CPing::GetTCPIPAddress ( LPCSTR szComputerAddress, char * szTCPIPAddr, size_t cbTCPIPAddr )

   {
   struct hostent       * lpHostEntry  = gethostbyname ( szComputerAddress );
   struct sockaddr_in   stAddr      = { 0 };

   memset ( szTCPIPAddr, 0, cbTCPIPAddr );

   if ( lpHostEntry )
      {
      memcpy ( &stAddr.sin_addr, lpHostEntry->h_addr_list [ 0 ], min ( sizeof stAddr.sin_addr, lpHostEntry->h_length ) );
      stAddr.sin_family = lpHostEntry->h_addrtype;
      }
   else
      {
      unsigned long lnAddr = 0LU;

      if ( ( lnAddr = inet_addr ( szComputerAddress ) ) == INADDR_NONE )
         {
         strncpy ( szTCPIPAddr, "???.???.???.???", cbTCPIPAddr );
         return false;
         }
      }

   // Convert the ination Address Into a Printable String

   strncpy ( szTCPIPAddr, inet_ntoa ( stAddr.sin_addr ), cbTCPIPAddr );

   return true;

   }  // bool CPing::GetTCPIPAddress ( LPCSTR szComputerAddress, char * szTCPIPAddr, size_t cbTCPIPAddr )

bool CPing::Ping ( LPCSTR strComputerAddress, int nTimesPinged, DWORD dwSleepPeriodBetweenPingsInms )

   {

   // Assure that this is a Valid CPing Object

   if ( ! IsValid() )
      {
      if ( m_hStdErr ) fprintf ( m_hStdErr, "This is NOT a valid CPing object!\n\a" );
      return false;
      }

   // Wait for the Critical Section - The Ping Command stays Locked Until Done

   while ( InterlockedIncrement ( ( LPLONG ) &m_lnPingSpinLock ) != 1 )
      {
      InterlockedDecrement ( ( LPLONG ) &m_lnPingSpinLock );
      SwitchToThread();
      }

   // Initialize Error Status to Success

   m_eLastPingError = VPE_SUCCESS;

   // Get the Host Information for the Requested Computer

   m_lpHostEntry = gethostbyname ( strComputerAddress );

   if ( m_lpHostEntry )
      {
      memcpy ( &m_stDestAddr.sin_addr, m_lpHostEntry->h_addr_list [ 0 ], min ( sizeof m_stDestAddr.sin_addr, m_lpHostEntry->h_length ) );
      m_stDestAddr.sin_family = m_lpHostEntry->h_addrtype;
      }
   else
      {
      unsigned long lnAddr = 0LU;

      if ( ( lnAddr = inet_addr ( strComputerAddress ) ) == INADDR_NONE )
         {
         m_eLastPingError = VPE_BAD_PING_ADDRESS;     
         InterlockedDecrement ( ( LPLONG ) &m_lnPingSpinLock );
         return false;
         }

      m_stDestAddr.sin_addr.S_un.S_addr = lnAddr;
      }

   // Convert the Destination Address Into a Printable String

   strncpy ( m_strDestTCPIPAddr, inet_ntoa ( m_stDestAddr.sin_addr ), sizeof m_strDestTCPIPAddr );

   // Send and Receive the ICMP Echo Packets

   bool fDataReceived = false;

   for ( int i = 0; i < nTimesPinged; i++ )
      {

      // Update the Header Information Specific to This Packet

      ( ( ICMPHeader * ) m_lpabICMPData )->i_cksum = 0;
      ( ( ICMPHeader * ) m_lpabICMPData )->i_seq   = ( USHORT ) m_nSequenceNumber;

      // Update the Tick Count in ms Since System Startup

      DWORD * lpdwTickCount = ( DWORD * ) ( ( ICMPHeader * ) m_lpabICMPData + 1 );

      * lpdwTickCount = GetTickCount();

      // Update the CheckSum for This Packet

      ( ( ICMPHeader * ) m_lpabICMPData )->i_cksum = CheckSum ( m_lpabICMPData, m_cbabICMPData );

      // Write the Ping Packet

      size_t cbWritten = sendto ( m_sRawSocket, ( char * ) m_lpabICMPData, m_cbabICMPData, 0, ( struct sockaddr * ) &m_stDestAddr, sizeof ( m_stDestAddr ) );

      // Handle Socket Errors

      if ( cbWritten == SOCKET_ERROR )
         {
         if ( WSAGetLastError() == WSAETIMEDOUT )
            {
            m_eLastPingError = VPE_SEND_PING_TIMED_OUT;
            InterlockedDecrement ( ( LPLONG ) &m_lnPingSpinLock );
            return false;
            }

         m_eLastPingError = VPE_SEND_PING_FAILED;
         InterlockedDecrement ( ( LPLONG ) &m_lnPingSpinLock );
         return false;
         }

      // Handle Write Underflow/Overflow Conditions

      if ( cbWritten != m_cbabICMPData )
         {
         m_eLastPingError = VPE_SEND_PING_BYTE_COUNT;
         InterlockedDecrement ( ( LPLONG ) &m_lnPingSpinLock );
         return false;
         }

      // Receive the Echo - recvfrom() Fills in the m_stFromAddr Info

      int cbstFromAddr = sizeof m_stFromAddr;

      do
         {
         m_cbabICMPEcho = recvfrom ( m_sRawSocket, ( char * ) m_lpabICMPEcho, MAX_PACKET, 0, ( struct sockaddr * ) &m_stFromAddr, &cbstFromAddr );
         } while ( m_eLastPingError == VPE_BAD_ICMP_PACKET_SEQUENCE );

      if ( m_cbabICMPEcho == SOCKET_ERROR )
         {
         if ( WSAGetLastError() == WSAETIMEDOUT )
            {
            if ( m_hStdOut ) fprintf ( m_hStdOut, "timed out\n" );
            m_eLastPingError = VPE_RECV_ECHO_TIMED_OUT;
            continue;
            }
         m_eLastPingError = VPE_RECV_ECHO_FAILED;
         InterlockedDecrement ( ( LPLONG ) &m_lnPingSpinLock );
         return false;
         }

      // Decode the Response Packet

      if ( DecodeICMPPingEcho ( m_lpabICMPEcho, m_cbabICMPEcho, &m_stFromAddr, m_nSequenceNumber ) )
         fDataReceived = true;

      // Update the Sequence Number

      m_nSequenceNumber++;

      // Sleep Between Pings

      if ( dwSleepPeriodBetweenPingsInms && i + 1 < nTimesPinged )
         {
         Sleep ( dwSleepPeriodBetweenPingsInms );
         }

      }  // for ( int i = 0; i < nTimesPinged; i++ )

   // Unlock the SpinLock

   InterlockedDecrement ( ( LPLONG ) &m_lnPingSpinLock );

   // Return Success Indication

   return fDataReceived;

   }  // bool CPing::Ping ( LPCSTR strComputerAddress, int nTimesPinged, DWORD dwSleepPeriodBetweenPingsInms )

Try.cpp

/***************************************************************************************
* Copyright (c) 2006 - 2011 Cass Tyler, PO Box 1026, Willard, NM 87063, (505) 384-5342 *
***************************************************************************************/

/************************************************************************************
*                                                                                   *
*  The CPing object uses the Internet Control Message Protocol (ICMP) Ping protocol *
*  to programatically query network addresses to see if they are active and online. *
*  The default timeout is 100ms and the Ping object only issues a single ping, so   *
*  response times are very good.                                                    *
*                                                                                   *
*  The CPing object came from a need to quickly obtain the status of all of the     *
*  participating components in a distributed control system.  You can sometimes     *
*  obtain the status in less than one second if everything is currently active and  *
*  online.                                                                          *
*                                                                                   *
*  You can also continuously monitor the status of a single component and alarm a   *
*  loss of communication in under a second.  Many communications tasks are time     *
*  intensive and can put processing into a race condition.  Ping uses light         *
*  resources and can prevent costly calls if the resource is offline.               *
*                                                                                   *
*  The szNodeNames[] table is build using the network names of the various network  *
*  components (these should be named in the C:\WINDOWS\system32\drivers\etc\hosts   *
*  file so that you can refer to them by mneumonic names instead of the harder to   *
*  remember network addresses.)  Please note that you can also use the network      *
*  addresses if you prefer.                                                         *
*                                                                                   *
*  Example Output:                                                                  *
*                                                                                   *
*     127.0.0.1       localhost       is Online                                     *
*     127.0.0.1       127.0.0.1       is Online                                     *
*     192.168.0.98    Laptop          is Online                                     *
*     192.168.0.1     qwest2016       is Online                                     *
*     192.168.0.100   Printer         is Online                                     *
*     192.168.1.2     NetBurner       is Offline                                    *
*     192.168.10.147  Smartcat        is Offline                                    *
*                                                                                   *
*  To compile from the command line:  "CL Try.cpp Ping.cpp"                         *
*                                                                                   *
************************************************************************************/

#define WIN32_LEAN_AND_MEAN            // Exclude rarely-used stuff from Windows headers

#include <WINDOWS.H>                   // Windows Function Prototypes and Defines

#include <lmcons.h>                    // LM20_CNLEN - Maximum Computer name length

#include "Ping.h"                      // The CPing Class

int main ( int /* argc */, char * /* argv */ [], char * /* envp */ [] )

   {
   static char * szNodeNames[]   = {

      "Laptop",                        // This Laptop WiFi Connection [Internet Connection]
      "localhost",                     // The Default "Local Host" Address
      "127.0.0.1",                     // The Default "Local Host" Address
      "Printer",                       // The Brothers HL-2070N Laser Printer in the Computer Room
      "qwest2016",                     // The Qwest DSL Modem

      "NetBurner",                     // The NetBurner Development System
      "Smartcat",                      // The Smartcat  Development System

   };

   static unsigned   uNodeNames  = sizeof szNodeNames / sizeof szNodeNames [ 0 ];

   CPing             Ping;

   // Check that the Ping Object Instanciated Correctly

   if ( ! Ping.IsValid() )
      {
      return 1;
      }

   // Enable Output

// Ping.PrintNarative   ( stdout ); // Lots of Informational Output
   Ping.PrintErrors     ( stderr ); // Prints Errors Only

   // Ping the Remote Computers 1 Time with 100 ms Between Loops - Output "Offline" if No Response

   for ( unsigned i = 0; i < uNodeNames; i++ )
      {
      char szTCPIPAddr [ LM20_CNLEN + 1 ] = { 0 };

      Ping.GetTCPIPAddress ( szNodeNames [ i ], szTCPIPAddr, sizeof szTCPIPAddr );

      printf ( "%-15s %-*s is %s\n", szTCPIPAddr, LM20_CNLEN, szNodeNames [ i ], Ping.Ping ( szNodeNames [ i ] ) ? "Online" : "Offline" );
      }

   printf ( "\n" );

   // Continuously Monitor a single Site

   for (i = 0; i < 10; i++ )
      {
      Sleep ( 1000LU );
      printf ( "localhost is %s\n", Ping.Ping ( "localhost" ) ? "Online" : "Offline" );
      }

   // Return Success!

   return 0;

   }  // int main ( int argc, char * argv [], char * envp [] )