Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Programmatically using ping (IcmpSendcho2 and IcmpParseReplies)

1,471 views
Skip to first unread message

Martijn Smitshoek

unread,
Sep 11, 2008, 11:59:00 AM9/11/08
to
The "blessed" way to send ping messages, and the only nonprivileged way to
do it in Vista, is to use a variant of IcmpSendcho.
Unfortunately, you can run into a lot of trouble with these functions. They
are poorly documented.
Because of that, you might have a program crash, or your app might not
register a valid reply even if it did get one.
Or your pogram won't link.

The biggest problem is the documentation.
Some important features in the help reference are poorly phrased and some
important warnings are missing.
Also some functions are specified wrong in the SDK header files.

The problems can all be overcome but it's a long story.
Here are my comments on the documentation of IcmpSendcho2, found on
http://msdn.microsoft.com/en-us/library/aa366051(VS.85).aspx

1. The reply buffer (ReplyBuffer)

Warning: When you use IcmpSendcho2 asynchronously, with IcmpParseReplies,
this buffer must exist until the ping attempt is completed.
If you de-allocate the buffer before you get your reply, or before your
timeout is expired, your program will crash in Vista.
Do _not_ close the ICMP handle or deallocate your buffer, until after your
timeout.

From what I could make of it, it looks like your ping attempt is complete:
- after you get a reply
- after calling IcmpParseReplies when the timeout period has expired.

The documentation does not specify when it is safe to delete your buffer. =>
clarification needed.

I think that the whole construct would be a lot safer if we could have an
equivalent of CancleIo.

2. The size of the reply buffer (ReplySize)

A quote from msdn.microsoft.com:
"ReplyBuffer [out]
A pointer to a buffer to hold any replies to the request. Upon return, the
buffer contains an array of ICMP_ECHO_REPLY structures followed by options
and data. The buffer must be large enough to hold at least one
ICMP_ECHO_REPLY structure plus RequestSize bytes of data. On a 64-bit
platform, upon return the buffer contains an array of ICMP_ECHO_REPLY32
structures followed by the options and data for the replies.

This buffer should also be large enough to also hold 8 more bytes of data
(the size of an ICMP error message) plus space for an IO_STATUS_BLOCK
structure."

Problem #1: I am doing application software, how am I supposed to know the
size of an IO_STATUS_BLOCK?! This is kernel stuff - I don't want to include
kernel headers.

Problem #2: "8 more bytes of data" 8 more than what? Suppose I knew the
size of IO_STATUS_BLOCK, it could mean either:

n * sizeof (ICMP_ECHO_REPLY) + __max(MY_OWN_REQUESTDATA_SIZE,
IO_STATUS_BLOCK_SIZE + 8)
or:
n * (sizeof (ICMP_ECHO_REPLY) + __max(MY_OWN_REQUESTDATA_SIZE,
IO_STATUS_BLOCK_SIZE) + 8)
or:
sizeof (ICMP_ECHO_REPLY) + MY_OWN_REQUESTDATA_SIZE + IO_STATUS_BLOCK_SIZE +
8
[or many other things]

I went on to experiment a bit, using this for a buffer size:

sizeof(ICMP_ECHO_REPLY) + MY_OWN_PAYLOAD_SIZE, PING_MIN_EXTRA_SIZE)

where PING_MIN_EXTRA_SIZE was a constant that I tried with different values.

For values less than 12, my asynchronous ping would fail with
ERROR_INSUFFICIENT_BUFFER.
For values from 12 to 19, the ping would appear to succeed, but a subsequent
IcmpParseReplies would fail to parse a valid reply.
For values of 20 and more the ping behaves normally.

Buffer size => a proper and simple formula is needed, using an explicit
number of bytes, not an obscure kernel structure.

3. Timeout value.

For asynchronous use of IcmpSendEcho2, the documentation states
" [..] this parameter is not used if either the ApcRoutine or Event
parameter are not NULL."

Wrong!

For Vista, you _do_ need to set a timeout.
If you only follow the documentation, use an event handle, and set the
timeout to 0, your response will never arrive and you _always_ get a
timeout.
Use an appropriate timeout value instead, and make sure that you do not
delete your buffers until the timeout has expired.

4. IcmpParseReplies in icmpapi.h from the SDK does not match the import
library Iphlpapi.lib. You get a link failure.
(Or at least, the "Microsoft Windows Software Development Kit for Windows
Vista Update (6000.16384.10)" has this problem.)

In order to link your application, you need to do the following:
- Locate icmpapi.h
- Locate the function IcmpParseReplies.
It should look something like this:

DWORD
IcmpParseReplies(
LPVOID ReplyBuffer,
DWORD ReplySize
);

Add the keyword WINAPI, like this:

DWORD
WINAPI
IcmpParseReplies(
LPVOID ReplyBuffer,
DWORD ReplySize
);

This changes the calling convention to __stdcall, the variant offered by the
import library.
You will find similar comments in the online version of the MSDN
documentation.


Alexander Nickolov

unread,
Oct 30, 2008, 3:21:00 PM10/30/08
to
For cancellation of async ICMP echo requests, see IcmpCloseHandle.

--
=====================================
Alexander Nickolov
Microsoft MVP [VC], MCSD
email: agnic...@mvps.org
MVP VC FAQ: http://vcfaq.mvps.org
=====================================

"Martijn Smitshoek" <undis...@xs4all.nl> wrote in message
news:48c94061$0$201$e4fe...@news.xs4all.nl...

Martijn Smitshoek

unread,
Nov 28, 2008, 4:24:56 AM11/28/08
to
"Alexander Nickolov" <agnic...@mvps.org> wrote in message
news:OczxlSsO...@TK2MSFTNGP06.phx.gbl...

> For cancellation of async ICMP echo requests, see IcmpCloseHandle.

> > Do _not_ close the ICMP handle or deallocate your buffer, until after
> > your timeout.

I wrote all of this because this `cancellation` use of IcmpCloseHandle is
exactly what failed to prevent my crashes in Vista (home premium, 64-bit,
SP1).
I was expecting this to be the proper way to do it, but it wasn't.


0 new messages