Skip Menu |

This queue is for tickets about the IO-Socket-IP CPAN distribution.

Report information
The Basics
Id: 91982
Status: resolved
Priority: 0/
Queue: IO-Socket-IP

People
Owner: Nobody in particular
Requestors: nick [...] ccl4.org
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in: 0.24
Fixed in: 0.25



This program works with IO::Socket::INET: $ cat server.pl use strict; use warnings; use Socket; require IO::Socket::INET; my $l = IO::Socket::INET->new(Type => Socket::SOCK_STREAM); $l->listen(5); printf "Connect to %d\n", $l->sockport; while (my $s = $l->accept()) { print $s "Hi\n"; $s->close }; __END__ $ /usr/local/blead/bin/perl5.19.8 server.pl Connect to 60619 and then in another window: $ telnet localhost 60619 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Hi Connection closed by foreign host. $ telnet localhost 60619 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Hi Connection closed by foreign host. If I replace IO::Socket::INET with IO::Socket::IP, then it fails: $ diff -u server.pl server-IP.pl --- server.pl 2014-01-09 16:56:07.000000000 +0100 +++ server-IP.pl 2014-01-09 16:57:55.000000000 +0100 @@ -2,9 +2,9 @@ use warnings; use Socket; -require IO::Socket::INET; +require IO::Socket::IP; -my $l = IO::Socket::INET->new(Type => Socket::SOCK_STREAM); +my $l = IO::Socket::IP->new(Type => Socket::SOCK_STREAM); $l->listen(5); printf "Connect to %d\n", $l->sockport; $ /usr/local/blead/bin/perl5.19.8 server-IP.pl Can't call method "listen" on an undefined value at server-IP.pl line 8. This isn't documented in IO::Socket::INET INCOMPATIBILITES Is it supposed to work? Or should it be documented? (This is with blead on OS X, but seems to be the same behaviour with v5.18.2 on Linux, In both cases IO::Socket:IP 0.24) Nicholas Clark
From: nick [...] ccl4.org
On Thu Jan 09 11:01:00 2014, nick@ccl4.org wrote: Show quoted text
> -my $l = IO::Socket::INET->new(Type => Socket::SOCK_STREAM); > +my $l = IO::Socket::IP->new(Type => Socket::SOCK_STREAM);
Show quoted text
> This isn't documented in IO::Socket::INET INCOMPATIBILITES > Is it supposed to work? > Or should it be documented?
I should add, that there's nothing in $! or $@ when this fails, so even if the assessment is that this should be a documented difference, it would be extremely helpful for it to report an error. Also, some variants work on IO::Socket::INET, but not IO::Socket::IP eg my $l = IO::Socket::INET->new(Blocking => 1) works, but not for IO::Socket::IP (again without any error I can spot) and likewise my $l = IO::Socket::INET->new(ReuseAddr => 1) works, but not for IO::Socket::IP. Nicholas Clark
On Thu Jan 09 11:01:00 2014, nick@ccl4.org wrote: Show quoted text
> This program works with IO::Socket::INET:
... Show quoted text
> my $l = IO::Socket::INET->new(Type => Socket::SOCK_STREAM); > $l->listen(5); > printf "Connect to %d\n", $l->sockport;
Righty.. IO::Socket::INET, wrapping a single socket family (AF_INET) can basically guess every socket parameter, if forced. Even the Type there is optional (as you later found) because IO::Socket::INET will guess Type => SOCK_STREAM if not specified. This leaves the socket() fully specified: socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) Later, you call listen(2) without a bind(2), so the kernel just substitutes the wildcard defaults, listening on INADDR_ANY and picking an unused port for you. IO::Socket::IP can't really make that guess, because it doesn't start off from a single socket family. Due to annoying history it isn't -quite- certain that a PF_INET6 listening socket will still receive connections to AF_INET addresses. It's therefore unclear what the user's intention would be of my $server = IO::Socket::IP->new( Family => PF_INET6, Listen => 1 ); my $client = IO::Socket::INET->new( PeerPort => $server->sockport ); Should this connect, or not? Some OSes say yes, some say no. Because IO::Socket::IP isn't going to make this decision though, it does lead to the awkward question of how to handle this case. A partial solution comes by way of 'gensym'ing a symbol to use as the object until a real socket() call can be made to open the actual socket, but that doesn't directly solve the whole problem because a packet family choice still needs to be made. Or maybe it becomes an error to try to construct one of these without any of {Local,Peer}{Host,Addr,AddrInfo} Family -- Paul Evans
Patch attached. About the best I can do, still not 100% convinced though... :/ -- Paul Evans
Subject: rt-91982.patch
=== modified file 'lib/IO/Socket/IP.pm' --- lib/IO/Socket/IP.pm 2014-01-10 20:52:40 +0000 +++ lib/IO/Socket/IP.pm 2014-01-10 23:17:57 +0000 @@ -512,8 +512,21 @@ } } - if( !@infos and defined $hints{family} ) { + if( !@infos ) { # If there was a Family hint then create a plain unbound, unconnected socket + # If there wasn't, use getaddrinfo()'s AI_ADDRCONFIG side-effect to guess a + # suitable family first. + if( !defined $hints{family} ) { + my ( $err, $addrinfo ) = getaddrinfo( "", "0", \%hints ); + if( $err ) { + $@ = "$err"; + $! = EINVAL; + return; + } + + $hints{family} = $addrinfo->{family}; + } + @infos = ( { family => $hints{family}, socktype => $hints{socktype}, === modified file 't/19no-addrs.t' --- t/19no-addrs.t 2013-03-31 20:40:52 +0000 +++ t/19no-addrs.t 2014-01-10 23:17:57 +0000 @@ -33,4 +33,13 @@ is( $sock->socktype, SOCK_STREAM, '$sock->socktype for Family => AF_INET6' ); } +# Lack of even a Family hint - _a_ socket is created but we don't guarantee +# what family +{ + my $sock = IO::Socket::IP->new( Type => SOCK_STREAM ); + + ok( defined $sock->fileno, '$sock->fileno for Type => SOCK_STREAM' ); + is( $sock->socktype, SOCK_STREAM, '$sock->socktype for Type => SOCK_STREAM' ); +} + done_testing;
Released in 0.25 -- Paul Evans