NAME
asr_run
,
asr_run_sync
, asr_abort
,
res_send_async
,
res_query_async
,
res_search_async
,
getrrsetbyname_async
,
gethostbyname_async
,
gethostbyname2_async
,
gethostbyaddr_async
,
getnetbyname_async
,
getnetbyaddr_async
,
getaddrinfo_async
,
getnameinfo_async
—
asynchronous resolver
functions
SYNOPSIS
#include
<sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <asr.h>
int
asr_run
(struct
asr_query *aq, struct
asr_result *ar);
int
asr_run_sync
(struct
asr_query *aq, struct
asr_result *ar);
void
asr_abort
(struct
asr_query *aq);
struct asr_query *
res_send_async
(const
unsigned char *pkt, int
pktlen, void
*asr);
struct asr_query *
res_query_async
(const
char *name, int
class, int type,
void *asr);
struct asr_query *
res_search_async
(const
char *name, int
class, int type,
void *asr);
struct asr_query *
getrrsetbyname_async
(const
char *hostname, unsigned
int rdclass, unsigned int
rdtype, unsigned int
flags, void
*asr);
struct asr_query *
gethostbyname_async
(const
char *name, void
*asr);
struct asr_query *
gethostbyname2_async
(const
char *name, int af,
void *asr);
struct asr_query *
gethostbyaddr_async
(const
void *addr, socklen_t
len, int af,
void *asr);
struct asr_query *
getnetbyname_async
(const
char *name, void
*asr);
struct asr_query *
getnetbyaddr_async
(in_addr_t
net, int type,
void *asr);
struct asr_query *
getaddrinfo_async
(const
char *hostname, const
char *servname, const
struct addrinfo *hints,
void *asr);
struct asr_query *
getnameinfo_async
(const
struct sockaddr *sa,
socklen_t salen,
char *host,
size_t hostlen,
char *serv,
size_t servlen,
int flags,
void *asr);
DESCRIPTION
The asr
functions provide a simple
interface for asynchronous address resolution and nameserver querying. They
should be used in place of the classical resolver functions of libc when
blocking is not desirable.
The principle of operation is as follows: All async requests are
made against an asr
context which basically defines
a list of sources to query and a strategy to do so. The user creates a query
through one of the dedicated functions, and gets a handle representing the
internal query. A query is a state-machine that can be run to try to fulfill
a particular request. This is done by calling in a generic API that performs
the state transitions until it needs to give the control back to the user,
either because a result is available, or because the next transition implies
a blocking call (a file descriptor needs to be read from or written to). The
user is responsible for dealing with the situation: either get the result,
or wait until the fd conditions are met, and then call back into the
resolving machinery when it is ready to proceed.
The
asr_run
()
function drives the resolving process. It runs the asynchronous query
represented by the aq handle until a result is
available, or until it cannot continue without blocking. The results are
returned to the user through the ar parameter, which
must be a valid pointer to user allocated memory. ar
is defined as:
struct asr_result { /* Fields set if the query is not done yet (asr_run returns 0) */ int ar_cond; /* ASR_WANT_READ or ASR_WANT_WRITE */ int ar_fd; /* the fd waiting for io condition */ int ar_timeout; /* time to wait for in milliseconds */ /* Error fields. Depends on the query type. */ int ar_errno; int ar_h_errno; int ar_gai_errno; int ar_rrset_errno; /* Result for res_*_async() calls */ int ar_count; /* number of answers in the dns reply */ int ar_rcode; /* response code in the dns reply */ void *ar_data; /* raw reply packet (must be freed) */ int ar_datalen; /* reply packet length */ struct sockaddr_storage ar_ns; /* nameserver that responded */ /* Result for other calls. Must be freed properly. */ struct addrinfo *ar_addrinfo; struct rrsetinfo *ar_rrsetinfo; struct hostent *ar_hostent; struct netent *ar_netent; };
The function returns one of the following values:
- 0
- The query cannot be processed further until a specific condition on a file
descriptor becomes true. The following members of the
ar structure are filled:
- ar_cond
- one of ASR_WANT_READ or ASR_WANT_WRITE,
- ar_fd
- the file descriptor waiting for an IO operation,
- ar_timeout
- the amount of time to wait for in milliseconds.
The caller is expected to call
asr_run
() again once the condition holds or the timeout expires. - 1
- The query is completed. The members relevant to the actual async query type are set accordingly, including error conditions. In any case, the query is cleared and its handle is invalidated.
Note that although the query itself may fail (the
error being properly reported in the ar structure),
the
asr_run
()
function itself cannot fail and it always preserves errno.
The
asr_run_sync
()
function is a wrapper around asr_run
() that handles
the read/write conditions, thus falling back to a blocking interface. It
only returns 1. It also preserves errno.
The
asr_abort
()
function clears a running query. It can be called when the query is waiting
on a file descriptor. Note that a completed query is already cleared when
asr_run
() returns, so
asr_abort
() must not be called in this case.
The remaining functions are used to initiate
different kinds of query on the asr resolver context.
The specific operational details for each of them are described below. All
functions return a handle to an internal query, or NULL if they could not
allocate the necessary resources to initiate the query. All other errors
(especially invalid parameters) are reported when calling
asr_run
().
They usually have the same interface as an existing resolver function, with
an additional asr argument, which specifies the
context to use for this request. For now, the argument must always be NULL,
which will use the default context for the current thread.
The
res_send_async
(),
res_query_async
()
and
res_search_async
()
functions are asynchronous versions of the standard libc resolver routines.
Their interface is very similar, except that the response buffer is always
allocated internally. The return value is found upon completion in the
ar_datalen member of the response structure. In
addition, the ar_ns structure contains the address of
the DNS server that sent the response, ar_rcode
contains the code returned by the server in the DNS response packet, and
ar_count contains the number of answers in the packet.
If a response is received it is placed in a newly allocated buffer and
returned as ar_data member. This buffer must be freed
by the caller. On error, the ar_errno and
ar_h_errno members are set accordingly.
The
getrrsetbyname_async
()
function is an asynchronous version of
getrrsetbyname(3). Upon completion, the return code is found
in ar_rrset_errno and the address to the newly
allocated result set is set in ar_rrsetinfo. As for
the blocking function, it must be freed by calling
freerrset(3).
The
gethostbyname_async
(),
gethostbyname2_async
()
and
gethostbyaddr_async
()
functions provide an asynchronous version of the network host entry
functions. Upon completion, ar_h_errno is set and the
resulting hostent address, if found, is set in the
ar_hostent field. Note that unlike their blocking
counterparts, these functions always return a pointer to newly allocated
memory, which must be released by the caller using
free(3).
Similarly, the
getnetbyname_async
()
and
getnetbyaddr_async
()
functions provide an asynchronous version of the network entry functions.
Upon completion, ar_h_errno is set and the resulting
netent address, if found, is set in the ar_netent
field. The memory there is also allocated for the request, and it must be
freed by free(3).
The
getaddrinfo_async
()
function is an asynchronous version of the
getaddrinfo(3) call. It provides a chain of addrinfo
structures with all valid combinations of socket address for the given
hostname, servname and
hints. Those three parameters have the same meaning as
for the blocking counterpart. Upon completion the return code is set in
ar_gai_errno. The ar_errno
member may also be set. On success, the ar_addrinfo
member points to a newly allocated list of addrinfo. This list must be freed
with
freeaddrinfo(3).
WORKING WITH THREADS
This implementation of the asynchronous resolver interface is thread-safe and lock-free internally, but the following restriction applies: Two different threads must not create queries on the same context or run queries originating from the same context at the same time. If they want to do that, all calls must be protected by a mutex around that context.
It is generally not a problem since the main point of the asynchronous resolver is to multiplex queries within a single thread of control, so sharing a resolver among threads is not useful.
SEE ALSO
getaddrinfo(3), gethostbyname(3), getnameinfo(3), getnetbyname(3), getrrsetbyname(3), res_send(3), resolv.conf(5)
CAVEATS
This DNS resolver implementation doesn't support the EDNS0 protocol extension yet.