Acme-Sort-Sleep
view release on metacpan or search on metacpan
local/lib/perl5/IO/Async/Resolver.pm view on Meta::CPAN
=cut
sub getaddrinfo
{
my $self = shift;
my %args = @_;
$args{on_resolved} or defined wantarray or
croak "Expected 'on_resolved' or to return a Future";
$args{on_error} or defined wantarray or
croak "Expected 'on_error' or to return a Future";
my $host = $args{host} || "";
my $service = $args{service}; defined $service or $service = "";
my $flags = $args{flags} || 0;
$flags |= AI_PASSIVE if $args{passive};
$args{family} = IO::Async::OS->getfamilybyname( $args{family} ) if defined $args{family};
$args{socktype} = IO::Async::OS->getsocktypebyname( $args{socktype} ) if defined $args{socktype};
# Clear any other existing but undefined hints
defined $args{$_} or delete $args{$_} for keys %args;
# It's likely this will succeed with AI_NUMERICHOST if host contains only
# [\d.] (IPv4) or [[:xdigit:]:] (IPv6)
# Technically we should pass AI_NUMERICSERV but not all platforms support
# it, but since we're checking service contains only \d we should be fine.
# These address tests don't have to be perfect as if it fails we'll get
# EAI_NONAME and just try it asynchronously anyway
if( ( $host =~ m/^[\d.]+$/ or $host =~ m/^[[:xdigit:]:]$/ or $host eq "" ) and
$service =~ m/^\d+$/ ) {
my ( $err, @results ) = Socket::getaddrinfo( $host, $service,
{ %args, flags => $flags | AI_NUMERICHOST }
);
if( !$err ) {
my $future = $self->loop->new_future->done( @results );
$future->on_done( $args{on_resolved} ) if $args{on_resolved};
return $future;
}
elsif( $err == EAI_NONAME ) {
# fallthrough to async case
}
else {
my $future = $self->loop->new_future->fail( $err, resolve => getaddrinfo => $err+0 );
$future->on_fail( $args{on_error} ) if $args{on_error};
return $future;
}
}
my $future = $self->resolve(
type => "getaddrinfo",
data => [
host => $host,
service => $service,
flags => $flags,
map { exists $args{$_} ? ( $_ => $args{$_} ) : () } qw( family socktype protocol ),
],
timeout => $args{timeout},
);
$future->on_done( $args{on_resolved} ) if $args{on_resolved};
$future->on_fail( $args{on_error} ) if $args{on_error};
return $future if defined wantarray;
# Caller is not going to keep hold of the Future, so we have to ensure it
# stays alive somehow
$self->adopt_future( $future->else( sub { Future->done } ) );
}
=head2 getnameinfo
( $host, $service ) = $resolver->getnameinfo( %args )->get
A shortcut wrapper around the C<getnameinfo> resolver, taking its arguments in
a more convenient form.
=over 8
=item addr => STRING
The packed socket address to look up.
=item flags => INT
Flags to control the C<getnameinfo(3)> function. See the C<NI_*> constants in
L<Socket>'s C<getnameinfo> for more detail.
=item numerichost => BOOL
=item numericserv => BOOL
=item dgram => BOOL
If true, set the C<NI_NUMERICHOST>, C<NI_NUMERICSERV> or C<NI_DGRAM> flags.
=item numeric => BOOL
If true, sets both C<NI_NUMERICHOST> and C<NI_NUMERICSERV> flags.
=item timeout => NUMBER
Time in seconds after which to abort the lookup with a C<Timed out> exception
=back
On failure, the detail field will give the error number, which should match
one of the C<Socket::EAI_*> constants.
->fail( $message, resolve => getnameinfo => $eai_errno )
As a specific optimisation, this method will try to perform a lookup of
numeric values synchronously, rather than asynchronously, if both the
C<NI_NUMERICHOST> and C<NI_NUMERICSERV> flags are given.
=head2 getnameinfo (void)
local/lib/perl5/IO/Async/Resolver.pm view on Meta::CPAN
does. For neatness it takes all its arguments as named values; taking the host
and service names from arguments called C<host> and C<service> respectively;
all the remaining arguments are passed into the hints hash. This name is also
aliased as simply C<getaddrinfo>.
The C<getaddrinfo_array> resolver behaves more like the C<Socket6> version of
the function. It takes hints in a flat list, and mangles the result of the
function, so that the returned value is more useful to the caller. It splits
up the list of 5-tuples into a list of ARRAY refs, where each referenced array
contains one of the tuples of 5 values.
As an extra convenience to the caller, both resolvers will also accept plain
string names for the C<family> argument, converting C<inet> and possibly
C<inet6> into the appropriate C<AF_*> value, and for the C<socktype> argument,
converting C<stream>, C<dgram> or C<raw> into the appropriate C<SOCK_*> value.
The C<getnameinfo> resolver returns its result in the same form as C<Socket>.
Because this module simply uses the system's C<getaddrinfo> resolver, it will
be fully IPv6-aware if the underlying platform's resolver is. This allows
programs to be fully IPv6-capable.
=cut
register_resolver getaddrinfo => sub {
my %args = @_;
my $host = delete $args{host};
my $service = delete $args{service};
$args{family} = IO::Async::OS->getfamilybyname( $args{family} ) if defined $args{family};
$args{socktype} = IO::Async::OS->getsocktypebyname( $args{socktype} ) if defined $args{socktype};
# Clear any other existing but undefined hints
defined $args{$_} or delete $args{$_} for keys %args;
my ( $err, @addrs ) = Socket::getaddrinfo( $host, $service, \%args );
die [ "$err", $err+0 ] if $err;
return @addrs;
};
register_resolver getaddrinfo_array => sub {
my ( $host, $service, $family, $socktype, $protocol, $flags ) = @_;
$family = IO::Async::OS->getfamilybyname( $family );
$socktype = IO::Async::OS->getsocktypebyname( $socktype );
my %hints;
$hints{family} = $family if defined $family;
$hints{socktype} = $socktype if defined $socktype;
$hints{protocol} = $protocol if defined $protocol;
$hints{flags} = $flags if defined $flags;
my ( $err, @addrs ) = Socket::getaddrinfo( $host, $service, \%hints );
die [ "$err", $err+0 ] if $err;
# Convert the @addrs list into a list of ARRAY refs of 5 values each
return map {
[ $_->{family}, $_->{socktype}, $_->{protocol}, $_->{addr}, $_->{canonname} ]
} @addrs;
};
register_resolver getnameinfo => sub {
my ( $addr, $flags ) = @_;
my ( $err, $host, $service ) = Socket::getnameinfo( $addr, $flags || 0 );
die [ "$err", $err+0 ] if $err;
return [ $host, $service ];
};
=head1 EXAMPLES
The following somewhat contrieved example shows how to implement a new
resolver function. This example just uses in-memory data, but a real function
would likely make calls to OS functions to provide an answer. In traditional
Unix style, a pair of functions are provided that each look up the entity by
either type of key, where both functions return the same type of list. This is
purely a convention, and is in no way required or enforced by the
L<IO::Async::Resolver> itself.
@numbers = qw( zero one two three four
five six seven eight nine );
register_resolver getnumberbyindex => sub {
my ( $index ) = @_;
die "Bad index $index" unless $index >= 0 and $index < @numbers;
return ( $index, $numbers[$index] );
};
register_resolver getnumberbyname => sub {
my ( $name ) = @_;
foreach my $index ( 0 .. $#numbers ) {
return ( $index, $name ) if $numbers[$index] eq $name;
}
die "Bad name $name";
};
=head1 AUTHOR
Paul Evans <leonerd@leonerd.org.uk>
=cut
0x55AA;
( run in 1.308 second using v1.01-cache-2.11-cpan-39bf76dae61 )