//<br />// Ping.h<br />//</p><p>#pragma pack(push)<br />#pragma pack(1)</p><p>#include <stdio.h><br />#include <stdlib.h><br />#include <stdarg.h><br />#include <winsock.h></p><p>class CPing<br />{<br /> #define ICMP_ECHOREPLY0<br /> #define ICMP_ECHOREQ8</p><p> // IP Header -- RFC 791<br /> typedef struct tagIPHDR<br /> {<br /> u_char VIHL;// Version and IHL<br /> u_charTOS;// Type Of Service<br /> shortTotLen;// Total Length<br /> shortID;// Identification<br /> shortFlagOff;// Flags and Fragment Offset<br /> u_charTTL;// Time To Live<br /> u_charProtocol;// Protocol<br /> u_shortChecksum;// Checksum<br /> structin_addr iaSrc;// Internet Address - Source<br /> structin_addr iaDst;// Internet Address - Destination<br /> }IPHDR, *PIPHDR;</p><p> // ICMP Header - RFC 792<br /> typedef struct tagICMPHDR<br /> {<br /> u_charType;// Type<br /> u_charCode;// Code<br /> u_shortChecksum;// Checksum<br /> u_shortID;// Identification<br /> u_shortSeq;// Sequence<br /> charData;// Data<br /> }ICMPHDR, *PICMPHDR;</p><p> // ICMP Echo Request<br /> #define REQ_DATASIZE 32// Echo Request Data size<br /> typedef struct tagECHOREQUEST<br /> {<br /> ICMPHDR icmpHdr;<br /> DWORDdwTime;<br /> charcData[REQ_DATASIZE];<br /> }ECHOREQUEST, *PECHOREQUEST;</p><p> // ICMP Echo Reply<br /> typedef struct tagECHOREPLY<br /> {<br /> IPHDRipHdr;<br /> ECHOREQUESTechoRequest;<br /> char cFiller[256];<br /> }ECHOREPLY, *PECHOREPLY;</p><p>private:<br /> bool bInitWinSockOK;<br /> u_short in_cksum(u_short *addr, int len);<br /> int SendEchoRequest(SOCKET s,LPSOCKADDR_IN lpstToAddr);<br /> DWORD RecvEchoReply(SOCKET s, LPSOCKADDR_IN lpsaFrom, u_char *pTTL);<br /> int WaitForEchoReply(SOCKET s);<br /> void Report(LPCTSTR format, ...);</p><p>public:<br /> CPing();<br /> virtual ~CPing();</p><p> void ping(LPCSTR pstrHost);</p><p>};</p><p>#pragma pack(pop)</p><p>
//<br />// PING.CPP -- Ping program using ICMP and RAW Sockets<br />//</p><p>#include "ping.h"<br />#pragma comment(lib, "ws2_32.lib")</p><p>CPing::CPing()<br />{<br /> bInitWinSockOK = false;</p><p> // Init WinSock<br /> WSADATA wsaData;<br /> WORD wVersionRequested = MAKEWORD(1,1);<br /> if ( WSAStartup(wVersionRequested, &wsaData) )<br /> {<br /> Report("/nError initializing WinSock/n");<br /> }<br /> else if (wsaData.wVersion != wVersionRequested)// Check version<br /> {<br /> Report("/nWinSock version not supported/n");<br /> }<br /> else<br /> {<br /> bInitWinSockOK = true;<br /> }<br />}</p><p>CPing::~CPing()<br />{<br /> if(bInitWinSockOK)<br /> WSACleanup();// Free WinSock<br />}</p><p>// ping()<br />// Calls SendEchoRequest() and<br />// RecvEchoReply() and retport results<br />void CPing::ping(LPCSTR pstrHost)<br />{<br /> SOCKET rawSocket;<br /> LPHOSTENT lpHost;<br /> struct sockaddr_in saDest;<br /> struct sockaddr_in saSrc;<br /> DWORD dwTimeSent;<br /> DWORD dwElapsed;<br /> u_char cTTL;<br /> int nLoop;<br /> int nRet;</p><p> if(!bInitWinSockOK)<br /> {<br /> Report("/nWinSock must be initializing/n");<br /> return;<br /> }</p><p> // Create a Raw socket<br /> rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);<br /> if (rawSocket == SOCKET_ERROR)<br /> {<br /> Report("socket() error: %d/n", WSAGetLastError());<br /> return;<br /> }</p><p> // Lookup host<br /> lpHost = gethostbyname(pstrHost);<br /> if (lpHost == NULL)<br /> {<br /> Report("/nHost not found: %s/n", pstrHost);<br /> return;<br /> }</p><p> // Setup destination socket address<br /> saDest.sin_addr.s_addr = *((u_long FAR *) (lpHost->h_addr));<br /> saDest.sin_family = AF_INET;<br /> saDest.sin_port = 0;</p><p> // Tell the user what we're doing<br /> Report("/nPinging %s [%s] with %d bytes of data:/n",<br /> pstrHost,<br /> inet_ntoa(saDest.sin_addr),<br /> REQ_DATASIZE);</p><p> // Ping multiple times<br /> for (nLoop = 0; nLoop < 4; nLoop++)<br /> {<br /> // Send ICMP echo request<br /> SendEchoRequest(rawSocket, &saDest);</p><p> // Use select() to wait for data to be received<br /> nRet = WaitForEchoReply(rawSocket);<br /> if (nRet == SOCKET_ERROR)<br /> {<br /> Report("select() error: %d/n", WSAGetLastError());<br /> break;<br /> }<br /> if (!nRet)<br /> {<br /> Report("/nTimeOut");<br /> break;<br /> }</p><p> // Receive reply<br /> dwTimeSent = RecvEchoReply(rawSocket, &saSrc, &cTTL);</p><p> // Calculate elapsed time<br /> dwElapsed = GetTickCount() - dwTimeSent;<br /> Report("/nReply from: %s: bytes=%d time=%ldms TTL=%d",<br /> inet_ntoa(saSrc.sin_addr),<br /> REQ_DATASIZE,<br /> dwElapsed,<br /> cTTL);<br /> }<br /> Report("/n");<br /> nRet = closesocket(rawSocket);<br /> if (nRet == SOCKET_ERROR)<br /> Report("closesocket() error: %d/n", WSAGetLastError());<br />}</p><p>void CPing::Report(LPCSTR format, ...)<br />{<br /> char _Buff[8192];<br /> memset(_Buff, 0, sizeof(_Buff));</p><p>va_list arg;<br />va_start(arg, format);<br />int charSize = _vsnprintf(_Buff, sizeof(_Buff), format, arg);<br />va_end(arg);</p><p> OutputDebugStringA(_Buff);<br />}</p><p>//<br />// Checksum routine for Internet Protocol family headers (C Version)<br />u_short CPing::in_cksum(u_short *addr, int len)<br />{<br /> register int nleft = len;<br /> register u_short *w = addr;<br /> register u_short answer;<br /> register int sum = 0;</p><p> /*<br /> * Our algorithm is simple, using a 32 bit accumulator (sum),<br /> * we add sequential 16 bit words to it, and at the end, fold<br /> * back all the carry bits from the top 16 bits into the lower<br /> * 16 bits.<br /> */<br /> while( nleft > 1 )<br /> {<br /> sum += *w++;<br /> nleft -= 2;<br /> }</p><p> /* mop up an odd byte, if necessary */<br /> if( nleft == 1 )<br /> {<br /> u_shortu = 0;<br /> *(u_char *)(&u) = *(u_char *)w ;<br /> sum += u;<br /> }</p><p> /*<br /> * add back carry outs from top 16 bits to low 16 bits<br /> */<br /> sum = (sum >> 16) + (sum & 0xffff);/* add hi 16 to low 16 */<br /> sum += (sum >> 16);/* add carry */<br /> answer = ~sum;/* truncate to 16 bits */<br /> return (answer);<br />}</p><p>// SendEchoRequest()<br />// Fill in echo request header<br />// and send to destination<br />int CPing::SendEchoRequest(SOCKET s,LPSOCKADDR_IN lpstToAddr)<br />{<br /> static ECHOREQUEST echoReq;<br /> static u_short nId = 1;<br /> static u_short nSeq = 1;<br /> int nRet;</p><p> // Fill in echo request<br /> echoReq.icmpHdr.Type= ICMP_ECHOREQ;<br /> echoReq.icmpHdr.Code= 0;<br /> echoReq.icmpHdr.Checksum= 0;<br /> echoReq.icmpHdr.ID= nId++;<br /> echoReq.icmpHdr.Seq= nSeq++;</p><p> // Fill in some data to send<br /> for (nRet = 0; nRet < REQ_DATASIZE; nRet++)<br /> echoReq.cData[nRet] = ' '+nRet;</p><p> // Save tick count when sent<br /> echoReq.dwTime= GetTickCount();</p><p> // Put data in packet and compute checksum<br /> echoReq.icmpHdr.Checksum = in_cksum((u_short *)&echoReq, sizeof(ECHOREQUEST));</p><p> // Send the echo request<br /> nRet = sendto(s,/* socket */<br /> (LPSTR)&echoReq,/* buffer */<br /> sizeof(ECHOREQUEST),<br /> 0,/* flags */<br /> (LPSOCKADDR)lpstToAddr, /* destination */<br /> sizeof(SOCKADDR_IN)); /* address length */</p><p> if (nRet == SOCKET_ERROR)<br /> Report("sendto() error: %d/n", WSAGetLastError());<br /> return (nRet);<br />}</p><p>// RecvEchoReply()<br />// Receive incoming data<br />// and parse out fields<br />DWORD CPing::RecvEchoReply(SOCKET s, LPSOCKADDR_IN lpsaFrom, u_char *pTTL)<br />{<br /> ECHOREPLY echoReply;<br /> int nRet;<br /> int nAddrLen = sizeof(struct sockaddr_in);</p><p> // Receive the echo reply<br /> nRet = recvfrom(s,// socket<br /> (LPSTR)&echoReply,// buffer<br /> sizeof(ECHOREPLY),// size of buffer<br /> 0,// flags<br /> (LPSOCKADDR)lpsaFrom,// From address<br /> &nAddrLen);// pointer to address len</p><p> // Check return value<br /> if (nRet == SOCKET_ERROR)<br /> Report("recvfrom() error: %d/n", WSAGetLastError());</p><p> // return time sent and IP TTL<br /> *pTTL = echoReply.ipHdr.TTL;<br /> return(echoReply.echoRequest.dwTime);<br />}</p><p>// WaitForEchoReply()<br />// Use select() to determine when<br />// data is waiting to be read<br />int CPing::WaitForEchoReply(SOCKET s)<br />{<br /> struct timeval Timeout;<br /> fd_set readfds;</p><p> readfds.fd_count = 1;<br /> readfds.fd_array[0] = s;<br /> Timeout.tv_sec = 5;<br /> Timeout.tv_usec = 0;</p><p> return(select(1, &readfds, NULL, NULL, &Timeout));<br />}<br />
//test code<br /> CPing ping;<br /> ping.ping( "www.sina.com.cn" );</p><p>//output<br />Pinging www.sina.com.cn [61.172.201.194] with 32 bytes of data:</p><p>Reply from: 61.172.201.194: bytes=32 time=15ms TTL=249<br />Reply from: 61.172.201.194: bytes=32 time=16ms TTL=249<br />Reply from: 61.172.201.194: bytes=32 time=0ms TTL=249<br />Reply from: 61.172.201.194: bytes=32 time=15ms TTL=249