489d2d
From d6a3ed8299ac6d5cac8db2e0f8e438dcfb8964a2 Mon Sep 17 00:00:00 2001
489d2d
From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= <ppisar@redhat.com>
489d2d
Date: Mon, 18 Sep 2017 17:21:26 +0200
489d2d
Subject: [PATCH] Ensure that a Host/Family-less constructor still constructs a
489d2d
 socket
489d2d
MIME-Version: 1.0
489d2d
Content-Type: text/plain; charset=UTF-8
489d2d
Content-Transfer-Encoding: 8bit
489d2d
489d2d
An upstream fix ported from 0.25 version to 0.21:
489d2d
489d2d
0.25    2014/01/11 17:19:29
489d2d
        [BUGFIXES]
489d2d
         * Ensure that a Host/Family-less constructor still constructs a
489d2d
           socket, by using gai()s AI_ADDRCONFIG hint
489d2d
489d2d
CPAN RT#91982
489d2d
489d2d
Signed-off-by: Petr Písař <ppisar@redhat.com>
489d2d
---
489d2d
 README              |  6 ++++++
489d2d
 lib/IO/Socket/IP.pm | 22 +++++++++++++++++++++-
489d2d
 t/19no-addrs.t      |  9 +++++++++
489d2d
 3 files changed, 36 insertions(+), 1 deletion(-)
489d2d
489d2d
diff --git a/README b/README
489d2d
index 32ccc65..d09fe2b 100644
489d2d
--- a/README
489d2d
+++ b/README
489d2d
@@ -189,6 +189,12 @@ CONSTRUCTORS
489d2d
     compatibility with `IO::Socket::INET'. Other named arguments that are
489d2d
     not recognised are ignored.
489d2d
 
489d2d
+    If neither `Family' nor any hosts or addresses are passed, nor any
489d2d
+    `*AddrInfo', then the constructor has no information on which to decide
489d2d
+    a socket family to create. In this case, it performs a `getaddinfo' call
489d2d
+    with the `AI_ADDRCONFIG' flag, no host name, and a service name of
489d2d
+    `"0"', and uses the family of the first returned result.
489d2d
+
489d2d
     If the constructor fails, it will set `$@' to an appropriate error
489d2d
     message; this may be from `$!' or it may be some other string; not every
489d2d
     failure necessarily has an associated `errno' value.
489d2d
diff --git a/lib/IO/Socket/IP.pm b/lib/IO/Socket/IP.pm
489d2d
index cc9c350..208d837 100644
489d2d
--- a/lib/IO/Socket/IP.pm
489d2d
+++ b/lib/IO/Socket/IP.pm
489d2d
@@ -311,6 +311,12 @@ C<SOCK_STREAM> and C<IPPROTO_TCP> respectively will be set, to maintain
489d2d
 compatibility with C<IO::Socket::INET>. Other named arguments that are not
489d2d
 recognised are ignored.
489d2d
 
489d2d
+If neither C<Family> nor any hosts or addresses are passed, nor any
489d2d
+C<*AddrInfo>, then the constructor has no information on which to decide a
489d2d
+socket family to create. In this case, it performs a C<getaddinfo> call with
489d2d
+the C<AI_ADDRCONFIG> flag, no host name, and a service name of C<"0">, and
489d2d
+uses the family of the first returned result.
489d2d
+
489d2d
 If the constructor fails, it will set C<$@> to an appropriate error message;
489d2d
 this may be from C<$!> or it may be some other string; not every failure
489d2d
 necessarily has an associated C<errno> value.
489d2d
@@ -512,8 +518,22 @@ sub _configure
489d2d
       }
489d2d
    }
489d2d
 
489d2d
-   if( !@infos and defined $hints{family} ) {
489d2d
+   if( !@infos ) {
489d2d
+
489d2d
       # If there was a Family hint then create a plain unbound, unconnected socket
489d2d
+      # If there wasn't, use getaddrinfo()'s AI_ADDRCONFIG side-effect to guess a
489d2d
+      # suitable family first.
489d2d
+      if( !defined $hints{family} ) {
489d2d
+         my ( $err, $addrinfo ) = getaddrinfo( "", "0", \%hints );
489d2d
+         if( $err ) {
489d2d
+            $@ = "$err";
489d2d
+            $! = EINVAL;
489d2d
+            return;
489d2d
+         }
489d2d
+
489d2d
+         $hints{family} = $addrinfo->{family};
489d2d
+      }
489d2d
+
489d2d
       @infos = ( {
489d2d
          family   => $hints{family},
489d2d
          socktype => $hints{socktype},
489d2d
diff --git a/t/19no-addrs.t b/t/19no-addrs.t
489d2d
index 65716cf..0ccb84f 100644
489d2d
--- a/t/19no-addrs.t
489d2d
+++ b/t/19no-addrs.t
489d2d
@@ -33,4 +33,13 @@ SKIP: {
489d2d
    is( $sock->socktype, SOCK_STREAM, '$sock->socktype for Family => AF_INET6' );
489d2d
 }
489d2d
 
489d2d
+# Lack of even a Family hint - _a_ socket is created but we don't guarantee
489d2d
+# what family
489d2d
+{
489d2d
+   my $sock = IO::Socket::IP->new( Type => SOCK_STREAM );
489d2d
+
489d2d
+   ok( defined $sock->fileno, '$sock->fileno for Type => SOCK_STREAM' );
489d2d
+   is( $sock->socktype, SOCK_STREAM, '$sock->socktype for Type => SOCK_STREAM' );
489d2d
+}
489d2d
+
489d2d
 done_testing;
489d2d
-- 
489d2d
2.13.5
489d2d