0

(Using Delphi 2009) I'm trying to write a simple network connection monitor using Indy TidIcmpClient. The idea is to ping an address, then inside an attached TidIcmpClient.OnReply handler test how much data was returned. If the reply contains > 0 bytes then I know the connection succeeded but if either the TidIcmpClient timed out or the reply contains 0 bytes I will assume the link is down

I'm having difficulty understanding the logic of TidIcmpClient as there is no 'OnTimeout' event.

Two sub questions...

Does TidIcmpClient.OnReply get called anyway, either (a) when data is received OR (b) when the timeout is reached, whichever comes first?

How can I distinguish a zero byte reply because of a timeout from a real reply within the timeout period that happens to contain zero bytes (or can't this happen)?

In other words is this sort of code OK or do I need to do something else to tell if it timed out or not

procedure TForm1.IdIcmpClient1Reply(ASender: TComponent; const AReplyStatus: TReplyStatus);
begin
if IdIcmpClient1.ReplyStatus.BytesReceived = 0 then
  //we must have timed out, link is down
else
  //got some data, connection is up
end;

procedure DoPing;
begin
IdIcmpClient1.ReceiveTimeout := 200;
IdIcmpClient1.Host := '8.8.8.8';
IdIcmpClient1.Ping;
end;
user3209752
  • 619
  • 2
  • 17
  • 29

2 Answers2

9

When Ping() exits, the ReplyStatus property contains the same information that is passed to the AReplyStatus parameter of the OnReply event (you are ignoring that parameter). Ping() simply calls the OnReply handler right before exiting, passing it the ReplyStatus property, so you don't actually need to use the OnReply event in your example. All that is doing is breaking up your code unnecessarily.

procedure DoPing;
begin
  IdIcmpClient1.ReceiveTimeout := 200;
  IdIcmpClient1.Host := '8.8.8.8';
  IdIcmpClient1.Ping;
  // process IdIcmpClient1.ReplyStatus here as needed...
end;

That being said, you are not processing the ReplyStatus data correctly. The BytesReceived field can be greater than 0 even if the ping fails. As its name implies, it simply reports how many bytes were actually received for the ICMP response. ICMP defines many different kinds of responses. The ReplyStatusType field will be set to the type of response actually received. There are 20 values defined:

type
  TReplyStatusTypes = (rsEcho,
    rsError, rsTimeOut, rsErrorUnreachable,
    rsErrorTTLExceeded,rsErrorPacketTooBig,
    rsErrorParameter,
    rsErrorDatagramConversion,
    rsErrorSecurityFailure,
    rsSourceQuench,
    rsRedirect,
    rsTimeStamp,
    rsInfoRequest,
    rsAddressMaskRequest,
    rsTraceRoute,
    rsMobileHostReg,
    rsMobileHostRedir,
    rsIPv6WhereAreYou,
    rsIPv6IAmHere,
    rsSKIP);

If the ping is successful, the ReplyStatusType will be rsEcho, and the ReplyData field will contain the (optional) data that was passed to the ABuffer parameter of Ping(). You might also want to pay attention to the FromIpAddress and ToIpAddress fields as well, to make sure the response is actually coming from the expected target machine.

If a timeout occurs, the ReplyStatusType will be rsTimeOut instead.

Try this:

procedure DoPing;
begin
  IdIcmpClient1.ReceiveTimeout := 200;
  IdIcmpClient1.Host := '8.8.8.8';
  IdIcmpClient1.Ping;
  if IdIcmpClient1.ReplyStatus.ReplyStatusType = rsEcho then
  begin
    // got some data, connection is up
  end
  else if IdIcmpClient1.ReplyStatus.ReplyStatusType = rsTimeout then
  begin
    // have a timeout, link is down
  end
  else
  begin
    // some other response, do something else...
  end;
end;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
0

IdIcmpClient companent has OnReply event. This event has AReplyStatus param as type TReplyStatus. TReplyStatus has ReplyStatusType property. This property's type is TReplyStatusTypes. TReplyStatusTypes has rsTimeOut value. So add code to OnReply event and check timeout or other error.

procedure TForm1.IdIcmpClient1Reply(ASender: TComponent;
  const AReplyStatus: TReplyStatus);
begin
  if AReplyStatus.ReplyStatusType = rsTimeOut then
  begin
    //do someting on timeout.
  end;
end;
mkysoft
  • 5,392
  • 1
  • 21
  • 30