Problem using IdIcmpClient

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

Problem using IdIcmpClient

Postby mark_c » Wed Mar 02, 2016 5:33 am

Hello everybody,
I try to using the code below but sometime BytesReceived is > 0 even if there is no computer connected to that address, why this occur?

Thank you

Code: Select all
BOOL MyPing(char *address)
{
// test for connected machine, if no return false

        Form1->IdIcmpClient1->Host = address;
        Form1->IdIcmpClient1->ReceiveTimeout=250;
        Form1->IdIcmpClient1->Ping();

        if(Form1->IdIcmpClient1->ReplyStatus.BytesReceived > 0)
        return TRUE;
        else
        return FALSE;
}
mark_c
BCBJ Veteran
BCBJ Veteran
 
Posts: 86
Joined: Thu Jun 21, 2012 1:13 am

Re: Problem using IdIcmpClient

Postby 2ffat » Wed Mar 02, 2016 6:10 am

I would be interested in knowing what you are getting. Are you getting a request timed out error or something similar?
James P. Cottingham

Look at me still talking
when there is science to do.
User avatar
2ffat
Forum Mod
Forum Mod
 
Posts: 427
Joined: Wed Jun 23, 2004 7:07 am
Location: South Hill, VA

Re: Problem using IdIcmpClient

Postby mark_c » Wed Mar 02, 2016 6:45 am

no, I do not see any errors, just as I said, sometimes the test:
Code: Select all
 if (Form1-> IdIcmpClient1-> ReplyStatus.BytesReceived> 0)

It is true even if there is no PC connected.

It could be that testing BytesReceived> 0 is not enough to know whether a PC is connected to the network or not: is that it?

thank you
mark_c
BCBJ Veteran
BCBJ Veteran
 
Posts: 86
Joined: Thu Jun 21, 2012 1:13 am

Re: Problem using IdIcmpClient

Postby 2ffat » Wed Mar 02, 2016 7:42 am

That would be my guess. When I do a "normal" ping on a PC not connected, I get some sort of error returned from the OS. I'm not familiar enough with IdIcmpClient to know what is happening. That's why I asked if the you were getting an error code or message.
James P. Cottingham

Look at me still talking
when there is science to do.
User avatar
2ffat
Forum Mod
Forum Mod
 
Posts: 427
Joined: Wed Jun 23, 2004 7:07 am
Location: South Hill, VA

Re: Problem using IdIcmpClient

Postby rlebeau » Wed Mar 02, 2016 2:41 pm

mark_c wrote:I try to using the code below but sometime BytesReceived is > 0 even if there is no computer connected to that address, why this occur?


You are ignoring the ReplyStatus.ReplyStatusType property, which tells you if a reply was actually received, and what type of reply it is (the ReplyStatus.MsgType will contain the actual ICMP message type, and the ReplyStatus.MsgCode will contain the ICMP status code).

If no reply is received at all, the ReplyStatusType will be rsTimeOut and the BytesReceived will be 0.

BytesReceived will be >0 if an actual reply is received from the network. But that does not necessarily mean the reply came from the host that is being pinged. For instance, it could be coming from a router that reports the host is unreachable (ReplyStatus.ReplyStatusType=rsErrorUnreachable, ReplyStatus.MsgType=Id_ICMP_UNREACH, where the ReplyStatus.MsgCode and ReplyStatus.Msg will tell you why it was unreachable).

Basically, if the ReplyStatus.ReplyStatusType is anything other than rsEcho (a real reply from the host), then the host was not reachable for one reason or another, so act accordingly.

Code: Select all
BOOL MyPing(char *address)
{
    // test for connected machine, if no return false
    Form1->IdIcmpClient1->Host = address;
    Form1->IdIcmpClient1->ReceiveTimeout = 250;
    Form1->IdIcmpClient1->Ping();
    return (Form1->IdIcmpClient1->ReplyStatus.ReplyStatusType == rsEcho) ? TRUE : FALSE;
}
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1457
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: Problem using IdIcmpClient

Postby mark_c » Thu Mar 03, 2016 1:22 am

thanks for the very detailed explanation; I wondered if this might be an optimal solution:

Code: Select all
BOOL MyPing(char *address)
{
// test for connected machine, if no return false

        Form1->IdIcmpClient1->Host = address;
        Form1->IdIcmpClient1->ReceiveTimeout=250;
        Form1->IdIcmpClient1->Ping();

        if(Form1->IdIcmpClient->ReplyStatus.BytesReceived > 0 &&
            Form1->IdIcmpClient->ReplyStatus.FromIpAddress == address)
        return TRUE;
        else
        return FALSE;
}



thank you


p.s.
I tried with your suggestion and after many tests I have the same problem
mark_c
BCBJ Veteran
BCBJ Veteran
 
Posts: 86
Joined: Thu Jun 21, 2012 1:13 am

Re: Problem using IdIcmpClient

Postby rlebeau » Thu Mar 03, 2016 12:33 pm

mark_c wrote:thanks for the very detailed explanation; I wondered if this might be an optimal solution


The solution I gave you is the optimal solution. Only the target host should be sending back an echo reply. Checking the BytesReceived will give you a false positive if *any* kind of reply is received from *any* device on the network, and checking the FromIpAddress will only work if pinging an IP address to begin with. You can ping a hostname instead, and if successful then FromIpAddress will be the host's IP.

mark_c wrote:I tried with your suggestion and after many tests I have the same problem


And what problem is that exactly?
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1457
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: Problem using IdIcmpClient

Postby mark_c » Thu Mar 03, 2016 12:55 pm

rlebeau wrote:And what problem is that exactly?


simply I have the same problem in my original question. Strangely the problems seem to disappear if I use the following solution:
Code: Select all
         if (Form1-> IdIcmpClient-> ReplyStatus.BytesReceived> 0 &&
             Form1-> IdIcmpClient-> ReplyStatus.FromIpAddress address == &&
             Form1-> IdIcmpClient1-> ReplyStatus.ReplyStatusType == rsEcho)



With this solution instead:

Code: Select all
if (Form1-> IdIcmpClient1-> ReplyStatus.ReplyStatusType == rsEcho)


I get false ping responses from disconnected pc.
mark_c
BCBJ Veteran
BCBJ Veteran
 
Posts: 86
Joined: Thu Jun 21, 2012 1:13 am

Re: Problem using IdIcmpClient

Postby rlebeau » Thu Mar 03, 2016 1:50 pm

mark_c wrote:simply I have the same problem in my original question.


<sigh>

You can't rely on BytesReceived in this situation anyway, because on a successful echo reply BytesReceived should match the number of bytes sent by the ABuffer parameter of Ping(), but you are not passing any data to Ping() so BytesReceived should always be 0 on success. It would be > 0 on failure if the error packet contains any data after the ICMP header.

So, just please, stop checking the BytesReceived altogether. Checking ReplyStatusType for rsEcho is ALL YOU NEED to know if the ping was successful. Anything else is an error.

mark_c wrote:With this solution instead:

Code: Select all
if (Form1-> IdIcmpClient1-> ReplyStatus.ReplyStatusType == rsEcho)


I get false ping responses from disconnected pc.


The ONLY way ReplyStatusType can be set to rsEcho is if TIdIcmpClient received an echo reply with a matching sequence number as the echo request. I can see that happening only if a device sitting on the network between your client and the target host is sending false echo replies on behalf of the target host. To combat that, you would have to validate the TIdIcmpClient.FPkt.SourceIP contains the expected target IP (if you ping a hostname, you will have to resolve its IP address via DNS first). The TIdIcmpClient.ReplyStatus.FromIpAddress field is taken from the ICMP payload data, and that can be easily faked, but TIdIcmpClient.FPkt.SourceIP is the real IP address from the ICMP packet header, and that cannot be faked without affecting network routing.

Only the target host is supposed to send the final echo reply if the echo request reaches it. Pinging depends on that working correctly.

Does the command-line ping.exe tool report the disconnected PC is not responding? Use a packet sniffer, like Wireshark, to compare the ICMP packets generated by ping.exe to those generated by TIdIcmpClient and see what is different about them. In an ideal situation, they should be equivalent to each other and produce equivalent responses.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1457
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: Problem using IdIcmpClient

Postby mark_c » Fri Mar 04, 2016 9:42 am

I apologize but I add to my original question, as read on the network by other users who have problems using the Ping (), which under Windows 7/8 the ReceiveTimeout not work. Someone wrote that the problem could be in the closing timing of the socket by the same windows. Someone asks you if by changing the timeout socket through SetSockOpt might work, but unfortunately, the documentation is insufficient to understand what to do really.

For example:
Code: Select all
int nTimeout = 1;
Form1->IdIcmpClient1->Binding->SetSockOpt(SOL_SOCKET, SO_RCVTIMEO, (char *)&nTimeout, sizeof(int));


Code: Select all
struct timeval tv;
tv.tv_usec = 20;  /* 20 msecs Timeout */
Form1->IdIcmpClient1->Binding->SetSockOpt(SOL_SOCKET, SO_RCVTIMEO,(char *)&tv,sizeof(timeval));


has no effect


Code: Select all
BOOL MyPing(char *address)
{
// test for connected machine, if no return false

        struct timeval tv;
        tv.tv_usec = 20;
        Form1->IdIcmpClient1->Binding->SetSockOpt(SOL_SOCKET, SO_RCVTIMEO,(char *)&tv,sizeof(timeval));

        Form1->IdIcmpClient1->Host = address;
        Form1->IdIcmpClient1->ReceiveTimeout=20;
        Form1->IdIcmpClient1->Ping();

        return (Form1->IdIcmpClient1->ReplyStatus.ReplyStatusType == rsEcho) ? TRUE : FALSE;
}



ultimately I believe that everything is due to how Windows works, if anyone knows what is the solution, thanks
mark_c
BCBJ Veteran
BCBJ Veteran
 
Posts: 86
Joined: Thu Jun 21, 2012 1:13 am

Re: Problem using IdIcmpClient

Postby rlebeau » Mon Mar 07, 2016 5:27 pm

mark_c wrote:I apologize but I add to my original question


You are asking a completely new question, so you should have started a new topic for it.

mark_c wrote:as read on the network by other users who have problems using the Ping (), which under Windows 7/8 the ReceiveTimeout not work.


I doubt that. ReceiveTimeout is implemented by simply calling the socket API select() function to wait for data to arrive before then reading it. If a select() timeout is not working correctly, it would mean the underlying OS is not doing its job.

mark_c wrote:Someone wrote that the problem could be in the closing timing of the socket by the same windows.


I do not understand what you are referring to.

mark_c wrote:
Code: Select all
int nTimeout = 1;
Form1->IdIcmpClient1->Binding->SetSockOpt(SOL_SOCKET, SO_RCVTIMEO, (char *)&nTimeout, sizeof(int));



That is setting a 1 **millisecond** timeout. You will never get responses that fast on a network.

mark_c wrote:
Code: Select all
struct timeval tv;
tv.tv_usec = 20;  /* 20 msecs Timeout */
Form1->IdIcmpClient1->Binding->SetSockOpt(SOL_SOCKET, SO_RCVTIMEO,(char *)&tv,sizeof(timeval));



That is setting a 20 **microsecond** timeout, not a 20 **millisecond** timeout.

Besides, on Windows, SO_RCVTIMEO does not use the timeval structure anyway, it expects a DWORD expressed in milliseconds instead.

Code: Select all
DWORD nTimeout = 20; /* 20 msecs Timeout */
Form1->IdIcmpClient1->Binding->SetSockOpt(SOL_SOCKET, SO_RCVTIMEO, (char *)&nTimeout, sizeof(DWORD));


BTW, are you using Indy 9? The code you have shown will not compile in Indy 10, because there is no TIdSocketHandle::SetSockOpt() overload for the parameters you are passing in.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1457
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: Problem using IdIcmpClient

Postby mark_c » Tue Mar 08, 2016 3:54 am

sorry. I'm using Borland Builder 6. In the future I will open a new 3d. I was referring to this discussion http://codeverge.com/embarcadero.delphi.winsock/tidicmpclient-receivetimeout-has-n/1075087
mark_c
BCBJ Veteran
BCBJ Veteran
 
Posts: 86
Joined: Thu Jun 21, 2012 1:13 am

Re: Problem using IdIcmpClient

Postby rlebeau » Tue Mar 08, 2016 5:31 pm

mark_c wrote:sorry. I'm using Borland Builder 6.


The version of Indy that shipped with BCB6 was Indy 8, not even 9, let alone 10. Are you using the shipped version?



That discussion talks about delays in CloseSocket(), and possibly using SetSockOpt() to configure the socket's linger options. SO_RCVTIMEO has nothing to do with linger. Look at SO_LINGER and SO_DONTLINGER instead. SO_DONTLINGER is enabled by default, so CloseSocket should not be blocking the caller, even if the OS decides to keep the socket open in the background.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1457
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: Problem using IdIcmpClient

Postby mark_c » Wed Mar 09, 2016 9:29 am

I am using indy 8.0.25

Code: Select all
        linger lin;
        lin.l_onoff=0;
        lin.l_linger=0;
        Form1->IdIcmpClient1->Binding->SetSockOpt(SOL_SOCKET, SO_LINGER, (char *)&lin, sizeof(lin));


error 10042 = Bad Protocol Option
mark_c
BCBJ Veteran
BCBJ Veteran
 
Posts: 86
Joined: Thu Jun 21, 2012 1:13 am

Re: Problem using IdIcmpClient

Postby rlebeau » Wed Mar 09, 2016 3:47 pm

mark_c wrote:
Code: Select all
        linger lin;
        lin.l_onoff=0;
        lin.l_linger=0;
        Form1->IdIcmpClient1->Binding->SetSockOpt(SOL_SOCKET, SO_LINGER, (char *)&lin, sizeof(lin));


error 10042 = Bad Protocol Option


That means the option is not supported by the underlying socket provider. TIdIcmpClient uses a SOCK_RAW socket, which likely does not support linger.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1457
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Next

Return to Technical

Who is online

Users browsing this forum: Bing [Bot], Google [Bot] and 11 guests

cron