Ping a computer using TCP stacks

.

This class addresses a common problem: how to ping a computer from a Win95 machine using the MS-TCP stacks. This will also work for NT 3.51 and 4.0. To make the problem more complex, MS did not include a mechanism for doing this in it's Winsock implementation.

The way around the problem is in using the ICMP DLL. This workaround is highly discouraged by Microsoft, but until Winsock 2.0, there was no other way to do a simple ping.

The problem: given a computer name, or given an IP address, ping the computer and return the ping response time. This requires access to the ICMP DLL, and to some of the socket structures provided in CSocket. Also, the class is derived from CSocket for future extension purposes.

Please note that to run this you'll need to get the ICMPAPI.H, ICMP.LIB, and IPEXPORT.H files from Microsoft, and place the lib and include files in your build settings. They are available on the Microsoft Developers Network CD's, and I believe on the Microsoft Web site as well.

The class includes four public functions:

unsigned long ResolveIP(CString strIP)
unsigned long ResolveName(CString strHostName)
CString GetIP(unsigned long ulIP)
DWORD PingHost(unsigned long ulIP, int iPingTimeout)

ResolveIP takes a CString IP address (i.e. "123.123.123.123"), and returns it's byte-ordered network address.

ResolveName takes a CString host name (i.e. ComputerName), resolves the name through DNS or WINS, and then returns the byte-ordered network address. Note that this uses a blocking GetHostByName.

GetIP takes the byte-ordered network address, and returns the IP address as a CString (i.e. "123.123.123.123").

PingHost takes the byte-ordered network address, a timeout integer, pings the address, and returns the ping response time.

/*
//------------------------------------------------------------------------------------------------------------------
//icmpecho.h
//------------------------------------------------------------------------------------------------------------------
*
class CIcmpEcho : public CSocket
{
// Attributes
public:

// Operations
public:
	CIcmpEcho();
	virtual ~CIcmpEcho();

	unsigned long ResolveIP(CString strIP);
	unsigned long ResolveName(CString strHostName);

	DWORD PingHost(unsigned long ulIP, int iPingTimeout);

	CString GetIP(unsigned long ulIP);

// Overrides
public:
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CIcmpEcho)
	//}}AFX_VIRTUAL

	// Generated message map functions
	//{{AFX_MSG(CIcmpEcho)
		// NOTE - the ClassWizard will add and remove member functions here.
	//}}AFX_MSG

// Implementation
protected:
};
/////////////////////////////////////////////////////////////////////////////







/*
//------------------------------------------------------------------------------------------------------------------
//icmpecho.cpp
//------------------------------------------------------------------------------------------------------------------
*
// IcmpEcho.cpp : implementation file
//

#include "IcmpEcho.h"

extern "C" {
#include "ipexport.h"
#include "icmpapi.h"
}

#define PING_TIMEOUT 100

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CIcmpEcho

CIcmpEcho::CIcmpEcho()
{
}

CIcmpEcho::~CIcmpEcho()
{
}


// Do not edit the following lines, which are needed by ClassWizard.
#if 0
BEGIN_MESSAGE_MAP(CIcmpEcho, CSocket)
	//{{AFX_MSG_MAP(CIcmpEcho)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()
#endif	// 0

/////////////////////////////////////////////////////////////////////////////
// CIcmpEcho member functions
unsigned long CIcmpEcho::ResolveIP(CString strIP)
{
	//Task 1:	Given IP Address i.e. "111.111.111.111",
	//	Return Network byte ordered address (ulIP)

	unsigned long ulIP;

	ulIP =(IPAddr)inet_addr(strIP);

	return ulIP;
}

unsigned long CIcmpEcho::ResolveName(CString strHostName)
{
	//Task 1:	Resolve HostName (through DNS or WINS, whichever appropriate)
	//Task 2:	Return network byte ordered address (ulIP)

	unsigned long ulIP;
	hostent* phostent;

	phostent = gethostbyname(strHostName);
	
	if (phostent == NULL)
		return 0;

	ulIP = *(DWORD*)(*phostent->h_addr_list);

	return ulIP;

}

DWORD CIcmpEcho::PingHost(unsigned long ulIP, int iPingTimeout)
{
	//Task 1:	Open ICMP Handle
	//Task 2:	Create Structure to receive ping reply
	//Task 3:	SendPing (SendEcho)
	//Task 4:	Close ICMP Handle
	//Task 5:	Return RoundTripTime

	unsigned long ip = ulIP;

	HANDLE icmphandle = IcmpCreateFile();

	char reply[sizeof(icmp_echo_reply)+8];

	icmp_echo_reply* iep=(icmp_echo_reply*)&reply
	iep->RoundTripTime = 0xffffffff;

	IcmpSendEcho(icmphandle,ip,0,0,NULL,reply,sizeof(icmp_echo_reply)+8,iPingTimeout);

	IcmpCloseHandle(icmphandle);

	return iep->RoundTripTime;

}

CString CIcmpEcho::GetIP(unsigned long ulIP)
{
	//Task 1:	Given a host order ulIP Address
	//	Return a IP address in format of xxx.xxx.xxx.xxx

	LPSTR szAddr;

	struct in_addr inetAddr;
	
	inetAddr.s_addr = (IPAddr)ulIP;

	szAddr = inet_ntoa(inetAddr);

	CString csIP = szAddr;

	return csIP;

}