I'm debugging some odd issue when a packet sent via an INET UDP socket is not sent to the given destination address.
The documentation (perldoc -f send
) says:
On unconnected sockets, you must specify a destination to send to, in which case it does a sendto(2) syscall.
That's all it says about the TO
parameter an connected sockets.
However after hours of debugging it seems what the manual does not say is:
On connected sockets the TO parameter is being ignored.
So I'd like to know:
send
is being ignored when PeerAddr
was specified when creating a IO::Socket::INET
(thus "connecting" the socket)?As it was requested to provide an example, here is one:
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket;
sub _socket(;$$)
{
my ($l, $p) = @_;
my %params = ('Proto' => 'udp');
@params{'LocalAddr', 'LocalPort'} = split(/:/, $l)
if ($l);
@params{'PeerAddr', 'PeerPort'} = split(/:/, $p)
if ($p);
return IO::Socket::INET->new(%params);
}
my $sock1 = _socket('localhost:1514');
my $sock2 = _socket('localhost:0', 'localhost:1514');
my $pkt;
while (defined(my $peer = $sock1->recv($pkt, 1000, 0))) {
print "received $pkt\n";
$sock2->send("response " . $pkt, 0, $peer);
}
Run it, and on the same host try netcat -u localhost 1514
.
Then enter one line like "junk", and you'll see that the sample program does not send back to the sender, but to itself, causing a loop.
Running the example under strace
, I see that connect()
is being used to "connect" $sock2
.
See your system's man pages for details on systems calls such as connect
and send
.
On POSIX systems, connect
says
For
SOCK_DGRAM
sockets, the peer address identifies where all datagrams are sent on subsequentsend()
functions, and limits the remote sender for subsequentrecv()
functions.
So using connect
overrides any destination address you might provide elsewhere.
Shouldn't send return an error when the socket is "connected" and a destination address is specified
The docs indicate error EISCONN
"may or may not be returned for connection mode sockets" when "a destination address was specified and the socket is already connected."
Now, it's not clear to me what makes a socket a "connection mode socket", but it appears to be based on protocol. But given an apparent lack of other guidance for connected UDP sockets, I find it reasonable to expect the same behaviour as for protocols like TCP. That is, the address is ignored or error EISCONN
is returned.