Paul Evans

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

$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 = $asyncns->fd

Returns a file descriptor number to poll for readability on.

$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.

$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.

$n = $asyncns->getnqueries

Return the number of outstanding queries.

$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

( $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

$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.

( $err, $host, $service ) = $asyncns->getnameinfo_done( $q )

Finishes a getnameinfo resolution, returning an error code, the hostname and service name, if requested.

$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.

$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.

$done = $asyncns->isdone( $q )

Returns true if the given query is ready.

$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.

$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.

$asyncns->setuserdata( $q, $data )

Stores an arbitrary Perl scalar with the query. It can later be retrieved using 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 = $query->asyncns

Returns the underlying Net::LibAsyncNS object backing the query

$done = $query->isdone

$query->setuserdata( $data )

$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};
          }
       }
    }
 }

AUTHOR

Paul Evans <leonerd@leonerd.org.uk>




Hosting generously
sponsored by Bytemark