This example shows how to "ping" another machine using Microsoft's ICMP.DLL. This DLL is an undocumented API for sending ICMP echo packets, also called "pings," after the submariner's term for sonar signals. This API works fine and is present on all current Windows boxes with Microsoft Winsocks, but because it is undocumented, Microsoft claims the right to replace it at any time. Maybe they will, and maybe they won't, but you should keep the portability issue and the undocumented issue in mind. If this bothers you, you might check out the raw sockets method for sending ping packets.
For more information on the ICMP.DLL API, check out sockets.com's ICMP API page. There is also a ping example program on MarkG's Win32 page; the following console mode program was distilled from his GUI version.
By the way, you might be wondering why the program has to load the ICMP.DLL manually and get the procedure addresses manually. I'm not sure of the reasons, but I spent an hour trying to get import libraries and DEF files to work. I can only suggest that some higher power is dead set against you linking this way. B-)
// Borland C++ 5.0: bcc32.cpp ping.cpp // Visual C++ 5.0: cl ping.cpp wsock32.lib #include <iostream.h> #include <winsock.h> #include <windowsx.h> #include "icmpdefs.h" int doit(int argc, char* argv[]) { // Check for correct command-line args if (argc < 2) { cerr << "usage: ping <host>" << endl; return 1; } // Load the ICMP.DLL HANDLE hIcmp = LoadLibrary("ICMP.DLL"); if (hIcmp == 0) { cerr << "Unable to locate ICMP.DLL!" << endl; return 2; } // Look up an IP address for the given host name struct hostent* phe; if ((phe = gethostbyname(argv[1])) == 0) { cerr << "Could not find IP address for " << argv[1] << endl; return 3; } // Get handles to the functions inside ICMP.DLL that we'll need typedef HANDLE (WINAPI* pfnHV)(VOID); typedef BOOL (WINAPI* pfnBH)(HANDLE); typedef DWORD (WINAPI* pfnDHDPWPipPDD)(HANDLE, DWORD, LPVOID, WORD, PIP_OPTION_INFORMATION, LPVOID, DWORD, DWORD); // evil, no? pfnHV pIcmpCreateFile; pfnBH pIcmpCloseHandle; pfnDHDPWPipPDD pIcmpSendEcho; pIcmpCreateFile = (pfnHV)GetProcAddress(hIcmp, "IcmpCreateFile"); pIcmpCloseHandle = (pfnBH)GetProcAddress(hIcmp, "IcmpCloseHandle"); pIcmpSendEcho = (pfnDHDPWPipPDD)GetProcAddress(hIcmp, "IcmpSendEcho"); if ((pIcmpCreateFile == 0) || (pIcmpCloseHandle == 0) || (pIcmpSendEcho == 0)) { cerr << "Failed to get proc addr for function." << endl; return 4; } // Open the ping service HANDLE hIP = pIcmpCreateFile(); if (hIP == INVALID_HANDLE_VALUE) { cerr << "Unable to open ping service." << endl; return 5; } // Build ping packet char acPingBuffer[64]; memset(acPingBuffer, '\xAA', sizeof(acPingBuffer)); PIP_ECHO_REPLY pIpe = (PIP_ECHO_REPLY)GlobalAllocPtr( GHND, sizeof(IP_ECHO_REPLY) + sizeof(acPingBuffer)); if (pIpe == 0) { cerr << "Failed to allocate global ping packet buffer." << endl; return 6; } pIpe->Data = acPingBuffer; pIpe->DataSize = sizeof(acPingBuffer); // Send the ping packet DWORD dwStatus = pIcmpSendEcho(hIP, *((DWORD*)phe->h_addr_list[0]), acPingBuffer, sizeof(acPingBuffer), NULL, pIpe, sizeof(IP_ECHO_REPLY) + sizeof(acPingBuffer), 5000); if (dwStatus != 0) { cout << "Addr: " << int(LOBYTE(LOWORD(pIpe->Address))) << "." << int(HIBYTE(LOWORD(pIpe->Address))) << "." << int(LOBYTE(HIWORD(pIpe->Address))) << "." << int(HIBYTE(HIWORD(pIpe->Address))) << ", " << "RTT: " << int(pIpe->RoundTripTime) << "ms, " << "TTL: " << int(pIpe->Options.Ttl) << endl; } else { cerr << "Error obtaining info from ping packet." << endl; } // Shut down... GlobalFreePtr(pIpe); FreeLibrary(hIcmp); return 0; } int main(int argc, char* argv[]) { WSAData wsaData; if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) { return 255; } int retval = doit(argc, argv); WSACleanup(); return retval; }
// Structures required to use functions in ICMP.DLL typedef struct { unsigned char Ttl; // Time To Live unsigned char Tos; // Type Of Service unsigned char Flags; // IP header flags unsigned char OptionsSize; // Size in bytes of options data unsigned char *OptionsData; // Pointer to options data } IP_OPTION_INFORMATION, * PIP_OPTION_INFORMATION; typedef struct { DWORD Address; // Replying address unsigned long Status; // Reply status unsigned long RoundTripTime; // RTT in milliseconds unsigned short DataSize; // Echo data size unsigned short Reserved; // Reserved for system use void *Data; // Pointer to the echo data IP_OPTION_INFORMATION Options; // Reply options } IP_ECHO_REPLY, * PIP_ECHO_REPLY;
Back to the Advanced Issues page...
Back to the Examples page...
![]() |
Go to my home page |
![]() |
Go to my Important RFC Lists page |
![]() |
Go to the main Programming Resources page |
Please send updates and corrections to <tangent@cyberport.com>.