You can use IcmpSendEcho2 to send out all your ping requests at the same time. Here is a sample demonstrating IcmpSendEcho2:
Code:
#include <winsock2.h>
#include <windows.h>
#include <Ipexport.h>
#include <icmpapi.h>
#include <stdio.h>
#if defined(_MSC_VER)
#pragma comment(lib, "Iphlpapi.lib")
#pragma comment(lib, "Ws2_32.lib")
#endif
/*
* Simple structure of arrays to create Targets collection.
*/
#define MAX_TARGETS 300
struct
{
struct in_addr IPAddresses[MAX_TARGETS];
BYTE Buffers [MAX_TARGETS][sizeof(ICMP_ECHO_REPLY) + 32];
HANDLE Events [MAX_TARGETS];
UINT cTargets;
} Targets;
/*
* Add an IP address to the Targets collection.
*/
BOOL new_Target(LPCSTR szIPAddress)
{
if (Targets.cTargets < MAX_TARGETS)
{
Targets.Events[Targets.cTargets] = CreateEvent(NULL, FALSE, FALSE, NULL);
Targets.IPAddresses[Targets.cTargets].S_un.S_addr = inet_addr(szIPAddress);
Targets.cTargets++;
return TRUE;
}
return FALSE;
}
/*
* There appears to be a problem with the import lib for IcmpParseReplies
* so we load it at run-time.
*/
DWORD wrapIcmpParseReplies(LPVOID ReplyBuffer, DWORD ReplySize)
{
typedef (WINAPI * pIPR)(LPVOID, DWORD);
static pIPR dl_IcmpParseReplies;
if (!dl_IcmpParseReplies)
{
HMODULE hICMP = LoadLibrary(TEXT("ICMP.dll"));
dl_IcmpParseReplies = (pIPR) GetProcAddress(hICMP, "IcmpParseReplies");
}
if (dl_IcmpParseReplies)
return dl_IcmpParseReplies(ReplyBuffer, ReplySize);
else
return 0;
}
/*
* main function.
*/
int main(void)
{
size_t i;
DWORD ret;
HANDLE hIcmp;
BYTE PingData[16];
/* Add IP Addresses to check. */
new_Target( "66.139.79.229" );
new_Target( "192.168.0.1" );
new_Target( "192.168.0.2" );
new_Target( "192.168.0.17" );
new_Target( "10.0.0.1" );
new_Target( "10.0.0.2" );
/* You can also check your entire subnet with something like: */
for (i = 1;i < 256;i++)
{
char buf[50];
sprintf(buf, "192.168.0.%d", i);
new_Target(buf);
}
hIcmp = IcmpCreateFile();
/* Send out all our async ping requests. Timeout is 250ms. Change if needed. */
for (i = 0; i < Targets.cTargets; i++)
{
IcmpSendEcho2(hIcmp, Targets.Events[i], NULL, 0,
Targets.IPAddresses[i].S_un.S_addr, PingData, sizeof(PingData),
NULL, Targets.Buffers[i], sizeof(Targets.Buffers[i]), 250);
}
/* Wait for all our ping requests to return or timeout. */
WaitForMultipleObjects(Targets.cTargets, Targets.Events, TRUE, 2500);
/* Check the results. */
for (i = 0; i < Targets.cTargets; i++)
{
ret = wrapIcmpParseReplies(Targets.Buffers[i], sizeof(Targets.Buffers[i]));
printf("%s: %s\n", ret != 0 ? "UP " : "DOWN", inet_ntoa(Targets.IPAddresses[i]));
}
IcmpCloseHandle(hIcmp);
getchar();
return 0;
}
Notes:
- I successfully used this code to check my subnet. Run-time was under a second.
- If you have slower paths in your network (WAN, VPN, etc) you may need to increase the timeout.
- Smart network components (routers, switches, etc) may detect this as a DOS attack and reject the ping packets.
- Error checking and cleanup code is incomplete.
- You may find it faster to get rid of NetServerEnum. You could ping the entire subnet and then lookup names with gethostbyaddr.