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>

