NAME
IO::Async::Resolver
- performing name resolutions asynchronously
SYNOPSIS
This object is used indirectly via an IO::Async::Loop
:
use IO::Async::Loop;
my $loop = IO::Async::Loop->new;
$loop->resolver->getaddrinfo(
host => "www.example.com",
service => "http",
)->on_done( sub {
foreach my $addr ( @_ ) {
printf "http://www.example.com can be reached at " .
"socket(%d,%d,%d) + connect('%v02x')\n",
@{$addr}{qw( family socktype protocol addr )};
}
});
$loop->resolve( type => 'getpwuid', data => [ $< ] )
->on_done( sub {
print "My passwd ent: " . join( "|", @_ ) . "\n";
});
$loop->run;
DESCRIPTION
This module extends an IO::Async::Loop
to use the system's name resolver functions asynchronously. It provides a number of named resolvers, each one providing an asynchronous wrapper around a single resolver function.
Because the system may not provide asynchronous versions of its resolver functions, this class is implemented using a IO::Async::Function
object that wraps the normal (blocking) functions. In this case, name resolutions will be performed asynchronously from the rest of the program, but will likely be done by a single background worker process, so will be processed in the order they were requested; a single slow lookup will hold up the queue of other requests behind it. To mitigate this, multiple worker processes can be used; see the workers
argument to the constructor.
The idle_timeout
parameter for the underlying IO::Async::Function
object is set to a default of 30 seconds, and min_workers
is set to 0. This ensures that there are no spare processes sitting idle during the common case of no outstanding requests.
METHODS
The following methods documented with a trailing call to ->get
return Future instances.
@result = $loop->resolve( %params )->get
Performs a single name resolution operation, as given by the keys in the hash.
The %params
hash keys the following keys:
- type => STRING
-
Name of the resolution operation to perform. See BUILT-IN RESOLVERS for the list of available operations.
- data => ARRAY
-
Arguments to pass to the resolver function. Exact meaning depends on the specific function chosen by the
type
; see BUILT-IN RESOLVERS. - timeout => NUMBER
-
Optional. Timeout in seconds, after which the resolver operation will abort with a timeout exception. If not supplied, a default of 10 seconds will apply.
$resolver->resolve( %params )
When not returning a future, additional parameters can be given containing the continuations to invoke on success or failure:
- on_resolved => CODE
-
A continuation that is invoked when the resolver function returns a successful result. It will be passed the array returned by the resolver function.
$on_resolved->( @result )
- on_error => CODE
-
A continuation that is invoked when the resolver function fails. It will be passed the exception thrown by the function.
@addrs = $resolver->getaddrinfo( %args )->get
A shortcut wrapper around the getaddrinfo
resolver, taking its arguments in a more convenient form.
- host => STRING
- service => STRING
-
The host and service names to look up. At least one must be provided.
- family => INT or STRING
- socktype => INT or STRING
- protocol => INT
-
Hint values used to filter the results.
- flags => INT
-
Flags to control the
getaddrinfo(3)
function. See theAI_*
constants in Socket'sgetaddrinfo
function for more detail. - passive => BOOL
-
If true, sets the
AI_PASSIVE
flag. This is provided as a convenience to avoid the caller from having to import theAI_PASSIVE
constant fromSocket
. - timeout => NUMBER
-
Time in seconds after which to abort the lookup with a
Timed out
exception
On success, the future will yield the result as a list of HASH references; each containing one result. Each result will contain fields called family
, socktype
, protocol
and addr
. If requested by AI_CANONNAME
then the canonname
field will also be present.
As a specific optimisation, this method will try to perform a lookup of numeric values synchronously, rather than asynchronously, if it looks likely to succeed.
Specifically, if the service name is entirely numeric, and the hostname looks like an IPv4 or IPv6 string, a synchronous lookup will first be performed using the AI_NUMERICHOST
flag. If this gives an EAI_NONAME
error, then the lookup is performed asynchronously instead.
$resolver->getaddrinfo( %args )
When not returning a future, additional parameters can be given containing the continuations to invoke on success or failure:
- on_resolved => CODE
-
Callback which is invoked after a successful lookup.
$on_resolved->( @addrs )
- on_error => CODE
-
Callback which is invoked after a failed lookup, including for a timeout.
$on_error->( $exception )
( $host, $service ) = $resolver->getnameinfo( %args )->get
A shortcut wrapper around the getnameinfo
resolver, taking its arguments in a more convenient form.
- addr => STRING
-
The packed socket address to look up.
- flags => INT
-
Flags to control the
getnameinfo(3)
function. See theNI_*
constants in Socket'sgetnameinfo
for more detail. - numerichost => BOOL
- numericserv => BOOL
- dgram => BOOL
-
If true, set the
NI_NUMERICHOST
,NI_NUMERICSERV
orNI_DGRAM
flags. - numeric => BOOL
-
If true, sets both
NI_NUMERICHOST
andNI_NUMERICSERV
flags. - timeout => NUMBER
-
Time in seconds after which to abort the lookup with a
Timed out
exception
As a specific optimisation, this method will try to perform a lookup of numeric values synchronously, rather than asynchronously, if both the NI_NUMERICHOST
and NI_NUMERICSERV
flags are given.
$resolver->getnameinfo( %args )
When not returning a future, additional parameters can be given containing the continuations to invoke on success or failure:
- on_resolved => CODE
-
Callback which is invoked after a successful lookup.
$on_resolved->( $host, $service )
- on_error => CODE
-
Callback which is invoked after a failed lookup, including for a timeout.
$on_error->( $exception )
FUNCTIONS
register_resolver( $name, $code )
Registers a new named resolver function that can be called by the resolve
method. All named resolvers must be registered before the object is constructed.
- $name
-
The name of the resolver function; must be a plain string. This name will be used by the
type
argument to theresolve
method, to identify it. - $code
-
A CODE reference to the resolver function body. It will be called in list context, being passed the list of arguments given in the
data
argument to theresolve
method. The returned list will be passed to theon_resolved
callback. If the code throws an exception at call time, it will be passed to theon_error
continuation. If it returns normally, the list of values it returns will be passed toon_resolved
.
BUILT-IN RESOLVERS
The following resolver names are implemented by the same-named perl function, taking and returning a list of values exactly as the perl function does:
getpwnam getpwuid
getgrnam getgrgid
getservbyname getservbyport
gethostbyname gethostbyaddr
getnetbyname getnetbyaddr
getprotobyname getprotobynumber
The following three resolver names are implemented using the Socket module.
getaddrinfo_hash
getaddrinfo_array
getnameinfo
The getaddrinfo_hash
resolver takes arguments in a hash of name/value pairs and returns a list of hash structures, as the Socket::getaddrinfo
function does. For neatness it takes all its arguments as named values; taking the host and service names from arguments called host
and service
respectively; all the remaining arguments are passed into the hints hash. This name is also aliased as simply getaddrinfo
.
The getaddrinfo_array
resolver behaves more like the 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 family
argument, converting inet
and possibly inet6
into the appropriate AF_*
value, and for the socktype
argument, converting stream
, dgram
or raw
into the appropriate SOCK_*
value.
The getnameinfo
resolver returns its result in the same form as Socket
.
Because this module simply uses the system's getaddrinfo
resolver, it will be fully IPv6-aware if the underlying platform's resolver is. This allows programs to be fully IPv6-capable.
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 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";
};
TODO
Look into (system-specific) ways of accessing asynchronous resolvers directly
AUTHOR
Paul Evans <leonerd@leonerd.org.uk>