This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
(perl #133936) make send() a bit saner
authorTony Cook <tony@develop-help.com>
Tue, 18 Jun 2019 04:59:00 +0000 (14:59 +1000)
committerTony Cook <tony@develop-help.com>
Tue, 18 Jun 2019 23:50:51 +0000 (09:50 +1000)
This undoes some of the effect of f1000aa2d in that TO will always
be supplied to CORE::send() if it's supplied, otherwise whether
TO is supplied to CORE::send() is based on whether the socket is
connected.

On Linux you appear to be able to sendto() to a different address on
a connected UDP socket, but this doesn't appear to be portable,
failing on darwin, and presumably on other BSDs.

dist/IO/lib/IO/Socket.pm
dist/IO/t/io_udp.t

index 345ffd4..28fa1ec 100644 (file)
@@ -277,13 +277,22 @@ sub send {
     @_ >= 2 && @_ <= 4 or croak 'usage: $sock->send(BUF, [FLAGS, [TO]])';
     my $sock  = $_[0];
     my $flags = $_[2] || 0;
-    my $peer  = $_[3] || $sock->peername;
+    my $peer;
 
-    croak 'send: Cannot determine peer address'
-        unless(defined $peer);
+    if ($_[3]) {
+        # the caller explicitly requested a TO, so use it
+        # this is non-portable for "connected" UDP sockets
+        $peer = $_[3];
+    }
+    elsif (!defined getpeername($sock)) {
+        # we're not connected, so we require a peer from somewhere
+        $peer = $sock->peername;
+
+       croak 'send: Cannot determine peer address'
+           unless(defined $peer);
+    }
 
-    my $type = $sock->socktype;
-    my $r = $type == SOCK_DGRAM || $type == SOCK_RAW
+    my $r = $peer
       ? send($sock, $_[1], $flags, $peer)
       : send($sock, $_[1], $flags);
 
@@ -526,9 +535,9 @@ C<FLAGS> is optional and defaults to C<0>, and
 
 =item *
 
-after a successful send with C<TO>, further calls to send() without
-C<TO> will send to the same address, and C<TO> will be used as the
-result of peername().
+after a successful send with C<TO>, further calls to send() on an
+unconnected socket without C<TO> will send to the same address, and
+C<TO> will be used as the result of peername().
 
 =back
 
index 571e430..2adc6a4 100644 (file)
@@ -89,9 +89,14 @@ is($buf, 'FOObar');
     ok($udpa->recv($buf = "", 8), "recv it");
     is($buf, "fromctoa", "check value received");
 
-    ok($udpc->send("fromctob", 0, $udpb->sockname), "send to non-connected socket");
-    ok($udpb->recv($buf = "", 8), "recv it");
-    is($buf, "fromctob", "check value received");
+  SKIP:
+    {
+        $^O eq "linux"
+         or skip "This is non-portable, known to 'work' on Linux", 3;
+        ok($udpc->send("fromctob", 0, $udpb->sockname), "send to non-connected socket");
+        ok($udpb->recv($buf = "", 8), "recv it");
+        is($buf, "fromctob", "check value received");
+    }
 }
 
 exit(0);