The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl

use warnings;
use strict;
use Test::More tests => 4;

sub POE::Kernel::ASSERT_DEFAULT () { 1 }

use POE;
use POE::Component::Resolver qw(AF_INET AF_INET6);

my $r4 = POE::Component::Resolver->new(
	max_resolvers => 1,
	idle_timeout  => 1,
	af_order      => [ AF_INET ],
);

# Try to detect whether we can resolve IPv6 addresses at all.

use Socket qw(getaddrinfo);
my $has_ipv6 = do {
	my ($error, @addresses) = getaddrinfo(
		"ipv6.test-ipv6.com", "www", { family => AF_INET6 }
	);
	($error or not @addresses) ? 0 : 1;
};

# If we can't, don't bother setting up resolvers for them.

my ($r6, $r46, $r64);
if ($has_ipv6) {
	$r6 = POE::Component::Resolver->new(
		max_resolvers => 1,
		idle_timeout  => 1,
		af_order      => [ AF_INET6 ],
	);

	$r46 = POE::Component::Resolver->new(
		max_resolvers => 1,
		idle_timeout  => 1,
		af_order      => [ AF_INET, AF_INET6 ],
	);

	$r64 = POE::Component::Resolver->new(
		max_resolvers => 1,
		idle_timeout  => 1,
		af_order      => [ AF_INET6, AF_INET ],
	);
}

# TODO - Not robust to try a single remote host.  I fully expect this
# to bite me later, unless someone wants to take a shot at it.

my $host = 'ipv6-test.com';
my $tcp  = getprotobyname("tcp");
my $service = $^O eq 'solaris' ? 80 : 'http';

POE::Session->create(
	inline_states => {
		_start => sub {
			$r4->resolve(
				host    => $host,
				service => $service,,
				hints   => { protocol => $tcp },
				misc    => [ AF_INET ],
			) or die $!;

			SKIP: {
				skip("IPv6 not detected; skipping IPv6 tests", 3) unless $has_ipv6;

				$r6->resolve(
					host    => $host,
					service => $service,
					hints   => { protocol => $tcp },
					misc    => [ AF_INET6 ],
				) or die $!;

				$r46->resolve(
					host    => $host,
					service => $service,
					hints   => { protocol => $tcp },
					misc    => [ AF_INET, AF_INET6 ],
				) or die $!;

				$r64->resolve(
					host    => $host,
					service => $service,
					hints   => { protocol => $tcp },
					misc    => [ AF_INET6, AF_INET ],
				) or die $!;
			}
		},

		resolver_response => sub {
			my ($error, $addresses, $request) = @_[ARG0..ARG2];

			foreach my $a (@$addresses) {
				diag("$request->{host} = ", scalar($r4->unpack_addr($a)));
			}

			my $expected_families = $request->{misc};

			my @got_families = map { $_->{family} } @$addresses;

			my $i = $#got_families;
			while ($i > 0 and $i--) {
				splice(@got_families, $i, 1) if (
					$got_families[$i] == $got_families[$i+1]
				);
			}

			is_deeply(
				\@got_families,
				$expected_families,
				"address families are as expected (@$expected_families)",
			);
		},

		_stop => sub { undef }, # for ASSERT_DEFAULT
	},
);

POE::Kernel->run();