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