5
votes

I have a small piece of code that checks if a computer is alive by pinging it. We use to have a room with 40 computer and I wanna check remotely through my program which on is alive.

Therefore I wrote a little ping function using indy

function TMainForm.Ping(const AHost : string) : Boolean;
var
  MyIdIcmpClient : TIdIcmpClient;
begin
  Result := True;

  MyIdIcmpClient := TIdIcmpClient.Create(nil);
  MyIdIcmpClient.ReceiveTimeout := 200;
  MyIdIcmpClient.Host := AHost;

  try
    MyIdIcmpClient.Ping;
    Application.ProcessMessages;
  except
    Result := False;
    MyIdIcmpClient.Free;
    Exit;
  end;
  if MyIdIcmpClient.ReplyStatus.ReplyStatusType <> rsEcho Then result := False;

  MyIdIcmpClient.Free;
end;

So I've developped that at home on my wifi network and everthing just work fine.

When I get back to work I tested and I get an error saying

Socket Errod # 10040 Message too long

At work we have fixed IPs and all the computer and I are in the same subnet.

I tried to disconnect from the fixed IP and connect to the wifi which of course is DHCP and not in the same subnet, and it is just working fine.

I have tried searching the internet for this error and how to solve it but didn't find much info.

Of course I have tried to change the default buffer size to a larger value but it didn't change anything I still get the error on the fixed IP within same subnet.

Moreover, I don't know if this can help finding a solution, but my code treats exceptions, but in that case it takes about 3-4 seconds to raise the error whereas the Timeout is set to 200 milliseconds. And I cannot wait that long over each ping.

By the way I use delphi 2010 and I think it is indy 10. I also have tested on XE2 but same error.

Any idea

----- EDIT -----

This question is answered, now I try to have this running in multithread and I have asked another question for that Delphi (XE2) Indy (10) Multithread Ping

3
may there be firewall blocking ICMP activity ? - Arioch 'The
does TidIcmpClient.OnReply get called ? - Arioch 'The
I have tried to change the default buffer size to a larger value How exactly ? show the code ? Perhaps you'd better try to decrease it instead. This example shows using Windows API to make pings and there buffer size is message size which reported being too large. Delphi Forum also holds discussion of IdICMP ping - Arioch 'The
This code has a memory leak: if an exception occurs, the component will not be freed. And the owner should be nil as you want to free the component yourself in the same method. - mjn
@mjn You're right I Edit my code. - HpTerm

3 Answers

7
votes

Set the PacketSize property to 24:

function TMainForm.Ping(const AHost : string) : Boolean;
var
  MyIdIcmpClient : TIdIcmpClient;
begin
  Result := True;

  MyIdIcmpClient := TIdIcmpClient.Create(self);
  MyIdIcmpClient.ReceiveTimeout := 200;
  MyIdIcmpClient.Host := AHost;
  MyIdIcmpClient.PacketSize := 24;
  MyIdIcmpClient.Protocol := 1;
  MyIdIcmpClient.IPVersion := Id_IPv4;

  try
    MyIdIcmpClient.Ping;
    // Application.ProcessMessages; // There's no need to call this!
  except
    Result := False;
    Exit;
  end;
  if MyIdIcmpClient.ReplyStatus.ReplyStatusType <> rsEcho Then result := False;

  MyIdIcmpClient.Free;
end;
1
votes

For XE5 and Indy10 this is still a problem, even with different Packet Size.

To answer the more cryptical fix:

ABuffer := MyIdIcmpClient1.Host + StringOfChar(' ', 255);

This is a "magic" fix to get around the fact that there is a bug in the Indy10 component (if I have understood Remy Lebeau right).

My speculation is that this has some connection with the size of the receive buffer. To test my theory I can use any character and don't need to include the host address at all. Only use as many character you need for the receive buffer. I use this small code (C++ Builder XE5) to do a Ping with great success (all other values at their defaults):

AnsiString Proxy = StringOfChar('X',IcmpClient->PacketSize);

IcmpClient->Host = Host_Edit->Text;
IcmpClient->Ping(Proxy);

As you can see I create a string of the same length as the PacketSize property. What you fill it with is insignificant.

Maybe this can be of help to @RemyLebeau when he work on the fix.

0
votes

use this code

ABuffer := MyIdIcmpClient1.Host + StringOfChar(' ', 255);

MyIdIcmpClient.Ping(ABuffer);