Skip Menu |

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

Report information
The Basics
Id: 101453
Status: resolved
Priority: 0/
Queue: IO-Async

People
Owner: Nobody in particular
Requestors: TEAM [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Wishlist
Broken in: 0.64
Fixed in: 0.65



Subject: Better reporting for ->connect(addr => { ... }) failures
I had some code that was passing a 'host' key as part of an addr parameter, it was reporting "Connection refused" rather than complaining about the unknown 'host' key and/or lack of a valid address to connect to, see attached test script. Generally it might be useful to have a way to take a host entry like that script and replace it with an address, leaving everything else intact, but that's probably out of scope for addr parameters? cheers, Tom
Subject: google.t
use strict; use warnings; use Test::More; use Test::Fatal; use IO::Async::Loop; my $loop = IO::Async::Loop->new; unlike(exception { $loop->connect( addr => { family => "inet", socktype => "stream", host => 'www.google.com', port => 443, } )->get }, qr/connection refused/i, "we get something better than 'connection refused' when supplying insufficient address info"); done_testing;
On Sun Jan 11 09:11:05 2015, TEAM wrote: Show quoted text
> I had some code that was passing a 'host' key as part of an addr > parameter, it was reporting "Connection refused" rather than > complaining about the unknown 'host' key and/or lack of a valid > address to connect to, see attached test script.
Oops. Probably should complain about unrecognised keys being present there. Show quoted text
> Generally it might be useful to have a way to take a host entry like > that script and replace it with an address, leaving everything else > intact, but that's probably out of scope for addr parameters?
Well, the entire point of the 'addr' or 'addrs' list is to avoid the hostname/service name lookup step, which involves a maybe-probably-blocking getaddrinfo() call. If you wanted to use an address, just pass a host / service pair instead of 'addr'. -- Paul Evans
Patched -- Paul Evans
Subject: rt101453.patch
=== modified file 'lib/IO/Async/OS.pm' --- lib/IO/Async/OS.pm 2014-10-17 16:54:33 +0000 +++ lib/IO/Async/OS.pm 2015-02-14 23:44:52 +0000 @@ -1,7 +1,7 @@ # You may distribute under the terms of either the GNU General Public License # or the Artistic License (the same terms as Perl itself) # -# (C) Paul Evans, 2012-2014 -- leonerd@leonerd.org.uk +# (C) Paul Evans, 2012-2015 -- leonerd@leonerd.org.uk package IO::Async::OS; @@ -409,20 +409,23 @@ @ai = @$ai; } elsif( ref $ai eq "HASH" ) { - @ai = @{$ai}{qw( family socktype protocol addr )}; + $ai = { %$ai }; # copy so we can delete from it + @ai = delete @{$ai}{qw( family socktype protocol addr )}; + + if( defined $ai[ADDRINFO_FAMILY] and !defined $ai[ADDRINFO_ADDR] ) { + my $family = $ai[ADDRINFO_FAMILY]; + my $method = "_extract_addrinfo_$family"; + my $code = $self->can( $method ) or croak "Cannot determine addr for extract_addrinfo on family='$family'"; + + $ai[ADDRINFO_ADDR] = $code->( $self, $ai ); + + keys %$ai and croak "Unrecognised '$family' addrinfo keys: " . join( ", ", keys %$ai ); + } } else { croak "Expected '$argname' to be an ARRAY or HASH reference"; } - if( defined $ai[ADDRINFO_FAMILY] and !defined $ai[ADDRINFO_ADDR] and ref $ai eq "HASH" ) { - my $family = $ai[ADDRINFO_FAMILY]; - my $method = "_extract_addrinfo_$family"; - my $code = $self->can( $method ) or croak "Cannot determine addr for extract_addrinfo on family='$family'"; - - $ai[ADDRINFO_ADDR] = $code->( $self, $ai ); - } - $ai[ADDRINFO_FAMILY] = $self->getfamilybyname( $ai[ADDRINFO_FAMILY] ); $ai[ADDRINFO_SOCKTYPE] = $self->getsocktypebyname( $ai[ADDRINFO_SOCKTYPE] ); @@ -446,8 +449,8 @@ my $self = shift; my ( $ai ) = @_; - my $port = $ai->{port} || 0; - my $ip = $ai->{ip} || "0.0.0.0"; + my $port = delete $ai->{port} || 0; + my $ip = delete $ai->{ip} || "0.0.0.0"; return pack_sockaddr_in( $port, inet_aton( $ip ) ); } @@ -469,10 +472,10 @@ my $self = shift; my ( $ai ) = @_; - my $port = $ai->{port} || 0; - my $ip = $ai->{ip} || "::"; - my $scopeid = $ai->{scopeid} || 0; - my $flowinfo = $ai->{flowinfo} || 0; + my $port = delete $ai->{port} || 0; + my $ip = delete $ai->{ip} || "::"; + my $scopeid = delete $ai->{scopeid} || 0; + my $flowinfo = delete $ai->{flowinfo} || 0; if( HAVE_SOCKADDR_IN6 ) { return pack_sockaddr_in6( $port, inet_pton( AF_INET6, $ip ), $scopeid, $flowinfo ); @@ -493,7 +496,7 @@ my $self = shift; my ( $ai ) = @_; - defined( my $path = $ai->{path} ) or croak "Expected 'path' for extract_addrinfo on family='unix'"; + defined( my $path = delete $ai->{path} ) or croak "Expected 'path' for extract_addrinfo on family='unix'"; return pack_sockaddr_un( $path ); } === modified file 't/02os.t' --- t/02os.t 2013-09-19 12:57:03 +0000 +++ t/02os.t 2015-02-14 23:44:52 +0000 @@ -4,6 +4,7 @@ use warnings; use Test::More; +use Test::Fatal; use IO::Async::OS; @@ -129,6 +130,11 @@ } ) ], [ AF_INET, SOCK_STREAM, 0, pack_sockaddr_in( 0, INADDR_ANY ) ], 'extract_addrinfo( HASH ) with inet only' ); + + ok( exception { IO::Async::OS->extract_addrinfo( { + family => "inet", + host => "foobar.com", + } ) }, 'extract_addrinfo for inet complains about unrecognised key' ); } SKIP: { @@ -158,4 +164,7 @@ 'extract_addrinfo( HASH ) with unix, path' ); } +ok( exception { IO::Async::OS->extract_addrinfo( { family => "hohum" } ) }, + 'extract_addrinfo on unrecognised family complains' ); + done_testing;
Released in 0.65 -- Paul Evans