NAME
Net::LibAsyncNS - a Perl wrapper around libasyncns
SYNOPSIS
use Net::LibAsyncNS;
use Socket qw( SOCK_RAW );
my $asyncns = Net::LibAsyncNS->new( 1 );
# By specifying this socktype hint, we only get one result per address family
my %hints = ( socktype => SOCK_RAW );
my $query = $asyncns->getaddrinfo( "localhost", undef, \%hints );
while( $asyncns->getnqueries ) {
$asyncns->wait( 1 );
if( $query->isdone ) {
my ( $err, @res ) = $asyncns->getaddrinfo_done( $query );
die "getaddrinfo - $err" if $err;
foreach my $res ( @res ) {
printf "family=%d, addr=%v02x\n", $res->{family}, $res->{addr};
}
}
}
DESCRIPTION
The name resolver functions getaddrinfo and getnameinfo as provided by
most C libraries are blocking functions; they will perform their work
and return an answer when it is ready. This makes it hard to use these
name resolvers in asynchronous or non-blocking code.
The libasyncns library provides a way to invoke these library functions
from within an asynchronous or non-blocking program. Individual
resolver queries are made by calling a function which returns an object
representing an outstanding query (a kind of future). A filehandle is
provided by the resolver to watch for readability; when it is readable,
a function should be called to collect completed queries. The example
in the SYNOPSIS above does not demonstrate this; see the EXAMPLES
section below for one that does.
CONSTRUCTOR
new
$asyncns = Net::LibAsyncNS->new( $n_proc )
Construct a new Net::LibAsyncNS object. It will be initialised with
$n_proc processes or threads to handle nameserver lookups.
METHODS
fd
$fd = $asyncns->fd
Returns a file descriptor number to poll for readability on.
new_handle_for_fd
$handle = $asyncns->new_handle_for_fd
Returns a new IO::Handle object wrapping the underlying file
descriptor. Note that the handle is not cached; a new object is created
each time this method is called. For well-behaved results, this should
only be called once.
wait
$success = $asyncns->wait( $block )
Wait for more queries to be ready. If $block is true, this method will
block until at least one query is ready, if false it will process any
pending IO without blocking. It returns true if the operation was
successful or false if an IO error happened; $! will be set in this
case.
getnqueries
$n = $asyncns->getnqueries
Return the number of outstanding queries.
getaddrinfo
$q = $asyncns->getaddrinfo( $host, $service, $hints )
Starts an asynchronous getaddrinfo resolution on the given $host and
$service names. If provided, $hints should be a HASH reference where
the following keys are recognised:
flags => INT
family => INT
socktype => INT
protocol => INT
getaddrinfo_done
( $err, @res ) = $asyncns->getaddrinfo_done( $q )
Finishes a getaddrinfo resolution, returning an error code, and a list
of results. Each result will be a HASH reference containing the
following keys:
family => INT
socktype => INT
protocol => INT
Socket type values to pass to socket
addr => STRING
Address to pass to connect
canonname => STRING
If requested, the canonical hostname for this address
getnameinfo
$q = $asyncns->getnameinfo( $addr, $flags, $wanthost, $wantserv )
Starts an asynchronous getnameinfo resolution on the given address. The
$wanthost and $wantserv booleans indicate if the hostname or service
name are required.
getnameinfo_done
( $err, $host, $service ) = $asyncns->getnameinfo_done( $q )
Finishes a getnameinfo resolution, returning an error code, the
hostname and service name, if requested.
res_query
res_search
$q = $asyncns->res_query( $dname, $class, $type )
$q = $asyncns->res_search( $dname, $class, $type )
Starts an asynchronous res_query or res_search resolution on the given
domain name, class and type.
res_done
$answer = $asyncns->res_done( $q )
Finishes a res_query or res_search resolution, returning the answer in
a packed string, or undef if it fails. If it fails $! will contain the
error details.
isdone
$done = $asyncns->isdone( $q )
Returns true if the given query is ready.
getnext
$q = $asyncns->getnext
Returns the next query object that is completed, or undef if none are
ready yet. This will only yet be valid after calling the wait method at
least once.
cancel
$asyncns->cancel( $q )
Cancels a currently outstanding query. After this is called, the query
in $q should not be further accessed, as memory associated with it will
have been reclaimed.
setuserdata
$asyncns->setuserdata( $q, $data )
Stores an arbitrary Perl scalar with the query. It can later be
retrieved using getuserdata.
getuserdata
$data = $asyncns->getuserdata( $q )
Returns the Perl scalar previously stored with the query, or undef if
no value has yet been set.
CONSTANTS
The following constants are provided by Net::LibAsyncNS::Constants.
Flags for getaddrinfo:
AI_PASSIVE
AI_CANONNAME
AI_NUMERICHOST
AI_NUMERICSERV
Error values:
EAI_BADFLAGS
EAI_NONAME
EAI_AGAIN
EAI_FAIL
EAI_NODATA
EAI_FAMILY
EAI_SERVICE
EAI_SOCKTYPE
EAI_ADDRFAMILY
EAI_MEMORY
Flags for getnameinfo:
NI_NUMERICHOST
NI_NUMERICSERV
NI_NAMEREQD
NI_DGRAM
QUERY OBJECTS
The following methods are available on query objects, returned by
getaddrinfo and getnameinfo.
asyncns
$asyncns = $query->asyncns
Returns the underlying Net::LibAsyncNS object backing the query
isdone
$done = $query->isdone
setuserdata
$query->setuserdata( $data )
getuserdata
$data = $query->getuserdata
Shortcuts to the equivalent method on the underlying Net::LibAsyncNS
object
EXAMPLES
Multiple Queries
The SYNOPSIS example only has one outstanding query. To wait for
multiple queries to complete, the getnext method can be used. Per-query
context data can be stored in the query itself by using the setuserdata
and getuserdata accessors.
use Net::LibAsyncNS;
use Socket qw( SOCK_RAW );
my $asyncns = Net::LibAsyncNS->new( 1 );
my %hints = ( socktype => SOCK_RAW );
my @hosts = qw( some hostnames here );
foreach my $host ( @hosts ) {
my $query = $asyncns->getaddrinfo( $host, undef, \%hints );
$query->setuserdata( $host );
}
while( $asyncns->getnqueries ) {
$asyncns->wait( 1 ) or die "asyncns_wait: $!";
while( my $query = $asyncns->getnext ) {
my ( $err, @res ) = $asyncns->getaddrinfo_done( $query );
my $host = $query->getuserdata;
print "$host - $err\n" and next if $err;
foreach my $res ( @res ) {
printf "%s is: family=%d, addr=%v02x\n",
$host, $res->{family}, $res->{addr};
}
}
}
In this example, the per-query data stored by setuserdata is just the
hostname, but any Perl scalar may be stored, such as a HASH ref
containing many keys, or CODE ref to a callback function of some kind.
Non-blocking IO
The examples above wait synchronously for the query/queries to
complete, in the wait method. However, most of the point of this
library is to allow asynchronous resolver calls to mix with other
asynchronous and non-blocking code. This is achieved by the containing
program waiting for a filehandle to become readable, and to call
$asyncns->wait( 0 ) when it is.
The following example shows integration with a simple IO::Poll-based
program.
use IO::Poll;
use Net::LibAsyncNS;
use Socket qw( SOCK_RAW );
my $asyncns = Net::LibAsyncNS->new( 1 );
my %hints = ( socktype => SOCK_RAW );
my @hosts = qw( some hostnames here );
foreach my $host ( @hosts ) {
my $query = $asyncns->getaddrinfo( $host, undef, \%hints );
$query->setuserdata( $host );
}
my $asyncns_handle = $asyncns->new_handle_for_fd;
my $poll = IO::Poll->new;
$poll->mask( $asyncns_handle => POLLIN );
while( $asyncns->getnqueries ) {
defined $poll->poll or die "poll() - $!";
if( $poll->events( $asyncns_handle ) ) {
while( my $query = $asyncns->getnext ) {
my ( $err, @res ) = $asyncns->getaddrinfo_done( $query );
my $host = $query->getuserdata;
print "$host - $err\n" and next if $err;
foreach my $res ( @res ) {
printf "%s is: family=%d, addr=%v02x\n",
$host, $res->{family}, $res->{addr};
}
}
}
}
SEE ALSO
* http://0pointer.de/lennart/projects/libasyncns is a C library for
Linux/Unix for executing name service queries asynchronously. It is
an asynchronous wrapper around getaddrinfo(3), getnameinfo(3),
res_query(3) and res_search(3) from libc and libresolv.
AUTHOR
Paul Evans <leonerd@leonerd.org.uk>