04bfb0
From bc26d2e6b287cc6693f41e1a2d48b0dd77d2e427 Mon Sep 17 00:00:00 2001
04bfb0
From: Tony Cook <tony@develop-help.com>
04bfb0
Date: Tue, 18 Jun 2019 14:59:00 +1000
04bfb0
Subject: [PATCH] (perl #133936) make send() a bit saner
04bfb0
MIME-Version: 1.0
04bfb0
Content-Type: text/plain; charset=UTF-8
04bfb0
Content-Transfer-Encoding: 8bit
04bfb0
04bfb0
This undoes some of the effect of f1000aa2d in that TO will always
04bfb0
be supplied to CORE::send() if it's supplied, otherwise whether
04bfb0
TO is supplied to CORE::send() is based on whether the socket is
04bfb0
connected.
04bfb0
04bfb0
On Linux you appear to be able to sendto() to a different address on
04bfb0
a connected UDP socket, but this doesn't appear to be portable,
04bfb0
failing on darwin, and presumably on other BSDs.
04bfb0
04bfb0
Signed-off-by: Petr Písař <ppisar@redhat.com>
04bfb0
---
04bfb0
 dist/IO/lib/IO/Socket.pm | 25 +++++++++++++++++--------
04bfb0
 dist/IO/t/io_udp.t       | 11 ++++++++---
04bfb0
 2 files changed, 25 insertions(+), 11 deletions(-)
04bfb0
04bfb0
diff --git a/dist/IO/lib/IO/Socket.pm b/dist/IO/lib/IO/Socket.pm
04bfb0
index 345ffd475d..28fa1ec149 100644
04bfb0
--- a/dist/IO/lib/IO/Socket.pm
04bfb0
+++ b/dist/IO/lib/IO/Socket.pm
04bfb0
@@ -277,13 +277,22 @@ sub send {
04bfb0
     @_ >= 2 && @_ <= 4 or croak 'usage: $sock->send(BUF, [FLAGS, [TO]])';
04bfb0
     my $sock  = $_[0];
04bfb0
     my $flags = $_[2] || 0;
04bfb0
-    my $peer  = $_[3] || $sock->peername;
04bfb0
+    my $peer;
04bfb0
 
04bfb0
-    croak 'send: Cannot determine peer address'
04bfb0
-	 unless(defined $peer);
04bfb0
+    if ($_[3]) {
04bfb0
+        # the caller explicitly requested a TO, so use it
04bfb0
+        # this is non-portable for "connected" UDP sockets
04bfb0
+        $peer = $_[3];
04bfb0
+    }
04bfb0
+    elsif (!defined getpeername($sock)) {
04bfb0
+        # we're not connected, so we require a peer from somewhere
04bfb0
+        $peer = $sock->peername;
04bfb0
+
04bfb0
+	croak 'send: Cannot determine peer address'
04bfb0
+	    unless(defined $peer);
04bfb0
+    }
04bfb0
 
04bfb0
-    my $type = $sock->socktype;
04bfb0
-    my $r = $type == SOCK_DGRAM || $type == SOCK_RAW
04bfb0
+    my $r = $peer
04bfb0
       ? send($sock, $_[1], $flags, $peer)
04bfb0
       : send($sock, $_[1], $flags);
04bfb0
 
04bfb0
@@ -526,9 +535,9 @@ C<FLAGS> is optional and defaults to C<0>, and
04bfb0
 
04bfb0
 =item *
04bfb0
 
04bfb0
-after a successful send with C<TO>, further calls to send() without
04bfb0
-C<TO> will send to the same address, and C<TO> will be used as the
04bfb0
-result of peername().
04bfb0
+after a successful send with C<TO>, further calls to send() on an
04bfb0
+unconnected socket without C<TO> will send to the same address, and
04bfb0
+C<TO> will be used as the result of peername().
04bfb0
 
04bfb0
 =back
04bfb0
 
04bfb0
diff --git a/dist/IO/t/io_udp.t b/dist/IO/t/io_udp.t
04bfb0
index 571e4303bb..2adc6a4a69 100644
04bfb0
--- a/dist/IO/t/io_udp.t
04bfb0
+++ b/dist/IO/t/io_udp.t
04bfb0
@@ -89,9 +89,14 @@ is($buf, 'FOObar');
04bfb0
     ok($udpa->recv($buf = "", 8), "recv it");
04bfb0
     is($buf, "fromctoa", "check value received");
04bfb0
 
04bfb0
-    ok($udpc->send("fromctob", 0, $udpb->sockname), "send to non-connected socket");
04bfb0
-    ok($udpb->recv($buf = "", 8), "recv it");
04bfb0
-    is($buf, "fromctob", "check value received");
04bfb0
+  SKIP:
04bfb0
+    {
04bfb0
+        $^O eq "linux"
04bfb0
+	  or skip "This is non-portable, known to 'work' on Linux", 3;
04bfb0
+        ok($udpc->send("fromctob", 0, $udpb->sockname), "send to non-connected socket");
04bfb0
+        ok($udpb->recv($buf = "", 8), "recv it");
04bfb0
+        is($buf, "fromctob", "check value received");
04bfb0
+    }
04bfb0
 }
04bfb0
 
04bfb0
 exit(0);
04bfb0
-- 
04bfb0
2.20.1
04bfb0