Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

udp send not reporting host unreachable errors

by saurabh.hirani (Beadle)
on May 05, 2009 at 09:57 UTC ( [id://761889]=perlquestion: print w/replies, xml ) Need Help??

saurabh.hirani has asked for the wisdom of the Perl Monks concerning the following question:

Hi guys,

Yesterday I had put up a post about a query I had for UDP sockets - send call on udp socket. To summarize it, when udp socket makes a send system call it returns true, irrespective of the status of the receiving host/port. And as per the UDP protocol, any reported asynchronous errors are are passed to the user.

So if I do a send, which returns true and then I do a recv or send, the first send's errors are reported during the later operations.

The code that I used was:
#!/usr/bin/perl -w use strict; use IO::Socket; my $client = new IO::Socket::INET( PeerAddr => '127.0.0.1', PeerPort => 3333, Proto => 'udp' ); (!$client) && die "failed to create sock: $!"; my ($request, $response); $request = 'the request to rule the world'; while(1 == 1) { if (! defined($client->send($request))) { print "send failed: $!\n"; } else { print "send succeeded\n"; } sleep 3; }
With no server running on 127.0.0.1:3333 the output I got was,
send succeeded send failed: Connection refused. send succeeded send failed: Connection refused. send succeeded . . .

which happens because of asynchronous errors received on network. I concluded, that if my send call fails, the error will be obtained at any point in time, but I will get the error.

I was wrong. Because if I change the PeerAddr to a unreachable host, the output I get is

send succeeded send succeeded send succeeded send succeeded . . .

The output I was expecting was

send succeeded send failed: Destination host unreachable. send succeeded send failed: Destination host unreachable. send succeeded send failed: Destination host unreachable. . . .

Because I should have got the error of host unreachable like I got for connection refused. I looked up to the udp and socket man pages on my system and found the following snippet in the udp man page:

All fatal errors will be passed to the user as an error return even when the socket is not connected. This includes asynchronous errors received from the network. You may get an error for an earlier packet that was sent on the same socket. This behaviour differs from many other BSD socket implementations which don’t pass any errors unless the socket is connected. Linux behaviour mandated by RFC 1122.

Snippet from socket man page SOCKET OPTIONS section for option SO_BSDCOMPAT:

If enabled ICMP errors received for a UDP socket will not be passed to the user program. In later kernel versions, support for this option has been phased out: Linux 2.4 silently ignores it, and Linux 2.6 generates a kernel warning (printk()) if a program uses this option.

Which means that I will get UDP send errors only if my destination host is up. I tried using the getsockopt() method from Socket module to check if SO_BSDCOMPAT option is set. But the Socket.pm module file does not have this option in its list of queriable options.

Perl is installed directly from the rpm and has not been compiled. My system parameters are

  1. OS: RHEL5, 64 bit virtual machine
  2. perl -v: v5.8.8 built for x86_64-linux-gnu-thread-multi
  3. uname -a: Linux myhostname 2.6.18-53.el5 #1 SMP Wed Oct 10 16:34:19 EDT 2007 x86_64 x86_64 x86_64 GNU/Linux

My questions:

  1. Shouldn't send() be reporting 'Destination host unreachable'?
  2. Does IO::Socket::INET have SO_BSDCOMPAT option set on in Perl v5.8.8?
  3. Is there a way of knowing if SO_BSDCOMPAT option is on for a socket?

thanks and regards,

Saurabh

Replies are listed 'Best First'.
Re: udp send not reporting host unreachable errors
by shmem (Chancellor) on May 05, 2009 at 10:17 UTC
    To summarize it, when udp socket makes a send system call it returns true, irrespective of the status of the receiving host/port.
    ...
    1. Shouldn't send() be reporting 'Destination host unreachable'?

    No, since UDP is connectionless. The packet is just sent, and the protocol doesn't provide that info. You could send an ICMP packet first to make sure the receiving side is reachable.

      You could send an ICMP packet first to make sure the receiving side is reachable.
      Well, you can, but you cannot be sure of anything regarding its answer. ICMP is a different protocol than UDP. Many routers/firewalls will block ICMP echos (or drop them on the ground) giving you false negatives about reachability. Or worse, a firewall may actually answer ICMP requests on behalf of its hosts on the inside - suggesting the host is up while it isn't. Or UDP traffic may be blocked while ICMP traffic isn't.

      Sending an ICMP packet may give you some insight, but you cannot be 100% sure.

      As for the OP: it seems to me that you want services from the network which TCP gives you, but UDP doesn't. Perhaps the OP should use TCP.

      I agree that UDP is connection less. But RFC 1122, which mandates the behaviour of Linux for UDP protocol states that whenever ICMP error messages are received, they should be reported to the user application.

      I do get "Connection refused" errors for sending data to a non existent UDP socket on a reachable host. Why shouldn't I get an error for a non existent port on an unreachable host?

      And as per the content of my post, if SO_BSDCOMPAT option is on, then you get errors if and only if the destination host is up but there is some problem in connecting to the socket.

      The UDP man page also states that SO_BSDCOMPAT option has been removed after Linux 2.2. I have Linux 2.6. So why is my application behaving as if SO_BSDCOMPAT option is set?

        I agree that UDP is connection less. But RFC 1122, which mandates the behaviour of Linux for UDP protocol states that whenever ICMP error messages are received, they should be reported to the user application.
        How do you propose this is done? Making the actual send() wait for a possible ICMP package is not practical, as you do not know whether there will come one, and you will not get a success message if the package was accepted. But if you don't wait forever, the program may have terminated before any message arrives.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://761889]
Approved by ELISHEVA
Front-paged by salva
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others perusing the Monastery: (5)
As of 2024-04-25 17:05 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found