use strict; use warnings FATAL => 'all'; use POE qw(Wheel::SocketFactory Wheel::ReadWrite Filter::Line); use POE::Component::IRC; use Test::More; my $tests = 4; BEGIN { my $GOT_SOCKET6; eval { Socket->import(qw(AF_INET6 unpack_sockaddr_in6 inet_pton)); $GOT_SOCKET6 = 1; }; if (!$GOT_SOCKET6) { eval { require Socket6; Socket6->import(qw(AF_INET6 unpack_sockaddr_in6 inet_pton)); $GOT_SOCKET6 = 1; }; plan skip_all => 'Socket6 is needed for IPv6 tests' if !$GOT_SOCKET6; } } # Argh, we need to be "smart" and see if we need GAI or not... # Perl-5.14.0 will core getaddrinfo() in it's Socket.pm eval { Socket->import('getaddrinfo') }; if ($@) { eval { require Socket::GetAddrInfo; Socket::GetAddrInfo->import(qw(:newapi getaddrinfo)) }; if ($@) { plan skip_all => 'Socket::GetAddrInfo is needed for IPv6 tests'; } } my $addr = eval { inet_pton(AF_INET6, "::1"); }; if (!defined $addr) { plan skip_all => "IPv6 tests require a configured localhost address ('::1')"; } plan tests => $tests; my $bot = POE::Component::IRC->spawn(); POE::Session->create( package_states => [ main => [qw( _start accept_client factory_failed client_input client_error irc_connected irc_socketerr irc_001 )] ] ); $poe_kernel->run(); sub _start { my ($heap) = $_[HEAP]; $heap->{sockfactory} = POE::Wheel::SocketFactory->new( SocketDomain => AF_INET6, BindAddress => '::1', BindPort => 0, SuccessEvent => 'accept_client', FailureEvent => 'factory_failed', ); my $packed_socket = $heap->{sockfactory}->getsockname; if (!$packed_socket) { diag("ERROR: Couldn't get the packed socket"); return; } eval { ($heap->{bindport}) = unpack_sockaddr_in6($packed_socket) }; if ($@) { diag("ERROR: $@"); return; } if ($heap->{bindport} == 0) { delete $heap->{sockfactory}; _skip_rest('$heap->{bindport} == 0'); return; } $bot->yield(register => 'all'); $bot->yield(connect => { Nick => 'testbot', Server => '::1', useipv6 => 1, Port => $heap->{bindport}, Username => 'testbot', Ircname => 'testbot 1.1', }); } sub accept_client { my ($heap, $socket) = @_[HEAP, ARG0]; my $wheel = POE::Wheel::ReadWrite->new( Handle => $socket, InputEvent => 'client_input', ErrorEvent => 'client_error', Filter => POE::Filter::Line->new( Literal => "\x0D\x0A" ), ); $heap->{client} = $wheel; } sub factory_failed { my ($heap, $syscall, $errno, $error) = @_[HEAP, ARG0..ARG2]; delete $_[HEAP]->{sockfactory}; _skip_rest("syscall error $errno: $error") if $tests; } sub client_input { my ($heap, $input) = @_[HEAP, ARG0]; SWITCH: { if ($input =~ /^NICK /) { pass('Server got NICK'); $tests--; $heap->{got_nick} = 1; last SWITCH; } if ($input =~ /^USER /) { pass('Server got USER'); $tests--; $heap->{got_user} = 1; last SWITCH; } if ($input =~ /^QUIT/ ) { delete $heap->{client}; delete $heap->{sockfactory}; return; } } if ($heap->{got_nick} && $heap->{got_user}) { # Send back irc_001 $heap->{client}->put(':test.script 001 testbot :Welcome to poconet Internet Relay Chat Network testbot!testbot@127.0.0.1'); } } sub client_error { my ($heap) = $_[HEAP]; delete $heap->{client}; delete $heap->{sockfactory}; } sub irc_connected { pass('Connected'); $tests--; } sub irc_socketerr { _skip_rest($_[ARG0]) if $tests; } sub irc_001 { pass('Logged in'); $bot->yield('shutdown'); } sub _skip_rest { my ($error) = @_; SKIP: { skip "AF_INET6 probably not supported ($error)", $tests; } $tests = 0; $bot->yield('shutdown'); }