summaryrefslogtreecommitdiff
path: root/doc/libs6dns
diff options
context:
space:
mode:
Diffstat (limited to 'doc/libs6dns')
-rw-r--r--doc/libs6dns/index.html104
-rw-r--r--doc/libs6dns/s6dns-domain.html137
-rw-r--r--doc/libs6dns/s6dns-engine.html255
-rw-r--r--doc/libs6dns/s6dns-fmt.html92
-rw-r--r--doc/libs6dns/s6dns-ip46.html69
-rw-r--r--doc/libs6dns/s6dns-message.html261
-rw-r--r--doc/libs6dns/s6dns-rci.html109
-rw-r--r--doc/libs6dns/s6dns-resolve.html387
8 files changed, 1414 insertions, 0 deletions
diff --git a/doc/libs6dns/index.html b/doc/libs6dns/index.html
new file mode 100644
index 0000000..db7ee35
--- /dev/null
+++ b/doc/libs6dns/index.html
@@ -0,0 +1,104 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6-dns: the s6dns library interface</title>
+ <meta name="Description" content="s6-dns: the s6dns library interface" />
+ <meta name="Keywords" content="s6-dns dns s6dns library libs6dns" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="../">s6-dns</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>s6dns</tt> library interface </h1>
+
+<h2> General information </h2>
+
+<p>
+ <tt>libs6dns</tt> is a DNS client library, designed for clarity
+and simplicity - which translates into smallness of the code.
+</p>
+
+<p>
+ A major focus of <tt>libs6dns</tt> is to avoid unnecessary use
+of heap memory. Memory is only allocated in the heap to store
+queries and response packets during a DNS resolution process, and
+to store the final answers into a user-provided
+<a href="http://skarnet.org/software/skalibs/libstddjb/stralloc.html">
+stralloc</a>; all the other operations use stack memory, and perform
+as few copies as possible.
+</p>
+
+<h2> Compiling </h2>
+
+<ul>
+ <li> Make sure the s6-dns headers, as well as the skalibs headers,
+are visible in your header search path. </li>
+ <li> Use <tt>#include &lt;s6-dns/s6dns.h&gt;</tt> </li>
+</ul>
+
+<h2> Linking </h2>
+
+<ul>
+ <li> Make sure the s6-dns libraries, as well as the skalibs libraries,
+are visible in your library search path. </li>
+ <li> Link against <tt>-ls6dns</tt>, <tt>-lskarnet</tt>, </li>
+<tt>`cat $SYSDEPS/socket.lib`</tt> and
+<tt>`cat $SYSDEPS/tainnow.lib`</tt>, $SYSDEPS being your skalibs
+sysdeps directory. </li>
+</ul>
+
+<h2> Programming </h2>
+
+<p>
+ The <tt>s6dns.h</tt> header is actually a concatenation of other headers:
+the libs6dns is separated into several modules, each of them with its
+own header.
+</p>
+
+<ul>
+ <li> The <tt>s6dns-constants.h</tt> header provides constants used in
+other parts of the library. </li>
+ <li> The <a href="s6dns-ip46.html">s6dns-ip46.h</a> header provides an
+abstraction for IPv4 and IPv6 transports. </li>
+ <li> The <a href="s6dns-domain.html">s6dns-domain.h</a> header provides
+basic string manipulation primitives for domain names. </li>
+ <li> The <a href="s6dns-message.html">s6dns-message.h</a> header provides
+function to parse a message following the DNS protocol. </li>
+ <li> The <a href="s6dns-engine.html">s6dns-engine.h</a> header provides
+the low-level asynchronous networking functions. </li>
+ <li> The <a href="s6dns-rci.html">s6dns-rci.h</a> header provides an
+interface to <tt>resolv.conf</tt> reading. </li>
+ <li> The <a href="s6dns-resolve.html">s6dns-resolve.h</a> header provides
+the user-level synchronous resolution functions. </li>
+ <li> The <a href="s6dns-fmt.html">s6dns-fmt.h</a> header provides
+formatting primitives to display RR contents. </li>
+</ul>
+
+<p>
+ (User-level asynchronous resolution functions are provided in the
+<a href="../skadns/">skadns</a> library.)
+</p>
+
+<p>
+ Two functional macros are actually directly declared in the <tt>s6dns.h</tt>
+header:
+</p>
+
+<ul>
+ <li> Call <tt>s6dns_init()</tt> before all your s6dns operations.
+s6dns_init() calls <a href="s6dns-rci.html">s6dns_rci_init()</a>,
+extracting <tt>resolv.conf</tt> information to an internal global
+variable. The function returns 1 on success, and 0 (and sets errno)
+on failure. </li>
+ <li> Call <tt>s6dns_finish()</tt> when you're done with the libs6dns.
+It frees the resources used. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/libs6dns/s6dns-domain.html b/doc/libs6dns/s6dns-domain.html
new file mode 100644
index 0000000..b1492c3
--- /dev/null
+++ b/doc/libs6dns/s6dns-domain.html
@@ -0,0 +1,137 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6-dns: the s6dns_domain library interface</title>
+ <meta name="Description" content="s6-dns: the s6dns_domain library interface" />
+ <meta name="Keywords" content="s6-dns dns s6dns_domain library libs6dns" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libs6dns</a><br />
+<a href="../">s6-dns</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>s6dns_domain</tt> library interface </h1>
+
+<p>
+ The following functions and structures are declared in the <tt>s6-dns/s6dns-domain.h</tt> header,
+and implemented in the <tt>libs6dns.a</tt> or <tt>libs6dns.so</tt> library.
+</p>
+
+<h2> General information </h2>
+
+<p>
+ <tt>s6dns_domain</tt> provides primitives to perform basic operations
+on domain names.
+</p>
+
+<h2> Data structures </h2>
+
+<p>
+ A <tt>s6dns_domain_t</tt> is a structure that s6dns uses internally to
+represent a domain name. It can be in <em>string form</em> (or
+<em>decoded form</em>), which is close to the printable form seen
+by users, or in <em>packet form</em> (or <em>encoded form</em>), which
+is the format used in the DNS protocol.
+</p>
+
+<p>
+ A <tt>s6dns_domain_t</tt> is a flat structure and can be declared
+on the stack.
+</p>
+
+<h2> Functions </h2>
+
+<p>
+<code> int s6dns_domain_fromstring (s6dns_domain_t *d, char const *s, unsigned int len) </code> <br />
+Makes a (string form) domain from string <em>s</em> of length <em>len</em>,
+and stores it into *<em>d</em>. Returns 1 if it succeeds, otherwise it
+returns 0 and sets errno appropriately - most likely ENAMETOOLONG, i.e.
+the name in <em>s</em> is not a well-formed domain name.
+</p>
+
+<p>
+<code> unsigned int s6dns_domain_tostring (char *s, unsigned int max, s6dns_domain_t const *d) </code> <br />
+Writes into string <em>s</em> the domain contained in *<em>d</em> (in string
+form). Returns the number of bytes written, or 0 in case of failure. If
+the output would be more than <em>max</em> bytes, 0 ENAMETOOLONG is returned.
+</p>
+
+<p>
+<code> int s6dns_domain_noqualify (s6dns_domain_t *d) </code> <br />
+Makes sure that *<em>d</em> is fully qualified. This is done without using
+qualification: a trailing dot is simply appended if the domain
+doesn't already have one. Returns 1 if it succeeds, or 0 if it fails.
+</p>
+
+<p>
+<code> unsigned int s6dns_domain_qualify (s6dns_domain_t *list, s6dns_domain_t const *d, char const *rules, unsigned int rulesnum) </code> <br />
+Performs qualification on domain *<em>d</em> according to the first
+<em>rulesnum</em> rules stored in string <em>rules</em>. Stores the output
+(at most <em>rulesnum</em> domains) into the array pointed to by <em>list</em>.
+Returns 0 on failure, or the number of written domains if it succeeds. This
+number can be lesser than <em>rulesnum</em>, for instance if *<em>d</em> is
+already fully qualified. <br />
+Valid <em>rules</em> and <em>rulesnum</em> can be obtained via functions
+declared in <a href="s6dns-rci.html">s6dns-rci.h</a>.
+</p>
+
+<p>
+<code> int s6dns_domain_encode (s6dns_domain_t *d) </code> <br />
+Encodes domain *<em>d</em> from string form to packet form. Returns 1
+if it succeeds or 0 if it fails - for instance, *<em>d</em> is not a
+valid string form (EINVAL).
+</p>
+
+<p>
+<code> unsigned int s6dns_domain_encodelist (s6dns_domain_t *list, unsigned int n) </code> <br />
+Encodes <em>n</em> domains pointed to by <em>list</em> from string form to packet form,
+stopping at the first failure.
+Returns the number of successfully encoded domains, normally <em>n</em>.
+</p>
+
+<p>
+<code> int s6dns_domain_decode (s6dns_domain_t *d) </code> <br />
+Decodes domain *<em>d</em> from packet form to string form. Returns 1
+if it succeeds or 0 if it fails - for instance, *<em>d</em> is not a
+valid packet form (EPROTO).
+</p>
+
+<p>
+<code> int s6dns_domain_fromstring_noqualify_encode (s6dns_domain_t *d, char const *s, unsigned int len) </code> <br />
+Higher-level function wrapping some of the above. Makes an encoded, fully qualified
+(without resorting to qualification) domain from string <em>s</em> of
+length <em>len</em>. Returns 1 if it succeeds and 0 if it fails.
+</p>
+
+<p>
+<code> unsigned int s6dns_domain_fromstring_qualify_encode (s6dns_domain_t *list, char const *s, unsigned int len, char const *rules, unsigned int rulesnum) </code> <br />
+Another wrapping function. It makes a list of encoded, fully qualified domains,
+from string <em>s</em> of length <em>len</em> using <em>rulesnum</em> qualification
+rules in <em>rules</em>. It writes at most <em>rulesnum</em> domains into the array
+pointed to by <em>list</em> and returns the number of written domains, or 0 on an
+error.
+</p>
+
+<p>
+<code> void s6dns_domain_arpafromip4 (s6dns_domain_t *d, char const *ip) </code> <br />
+Writes into <em>d</em> the <tt>in-addr.arpa.</tt> domain corresponding to IPv4 address
+<em>ip</em> (4 bytes, in network byte order), in string form.
+</p>
+
+<p>
+<code> void s6dns_domain_arpafromip6 (s6dns_domain_t *d, char const *ip, unsigned int mask) </code> <br />
+Writes into <em>d</em> the <tt>ip6.arpa.</tt> domain corresponding to the first
+<em>mask</em> bits of IPv6 address <em>ip</em> (16 bytes, in network byte order),
+in string form.
+Only multiples of 4 count for <em>mask</em>, i.e. the output will be the same
+if mask is (for instance) 125, 126, 127 or 128.
+</p>
+
+</body>
+</html>
diff --git a/doc/libs6dns/s6dns-engine.html b/doc/libs6dns/s6dns-engine.html
new file mode 100644
index 0000000..f0f9573
--- /dev/null
+++ b/doc/libs6dns/s6dns-engine.html
@@ -0,0 +1,255 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6-dns: the s6dns_engine library interface</title>
+ <meta name="Description" content="s6-dns: the s6dns_engine library interface" />
+ <meta name="Keywords" content="s6-dns dns s6dns_engine library libs6dns" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libs6dns</a><br />
+<a href="../">s6-dns</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>s6dns_engine</tt> library interface </h1>
+
+<p>
+ The following functions are declared in the <tt>s6-dns/s6dns-engine.h</tt> header,
+and implemented in the <tt>libs6dns.a</tt> or <tt>libs6dns.so</tt> library.
+</p>
+
+<h2> General information </h2>
+
+<p>
+ <tt>s6dns_engine</tt> is the nitty-gritty of DNS query management. These
+are the low-level asynchronous primitives sending DNS queries over the
+network, and getting answers.
+</p>
+
+<p>
+ <tt>s6dns_engine</tt> has been inspired by Dan J. Bernstein's
+<a href="http://cr.yp.to/djbdns/dns_transmit.html">dns_transmit</a>
+library, but does not borrow any code from it. Unlike
+<tt>dns_transmit</tt>, <tt>s6dns_engine</tt> does not assume that
+network send operations are instant successes; <tt>s6dns_engine</tt>
+descriptors can be selected for writing as well as for reading.
+Also, if the underlying <a href="http://skarnet.org/software/skalibs">
+skalibs</a> has been compiled with IPv6 support, <tt>s6dns_engine</tt>
+supports native IPv6 transport.
+</p>
+
+<p>
+ The <tt>s6dns_engine</tt> functions are used in the implementation of the
+<tt>s6dns_resolven_loop</tt> function - which is nothing more than a
+simple event loop around the <tt>s6dns_engine</tt> primitives - and the
+<a href="../skadns/skadnsd.html">skadnsd</a> daemon. Both pieces of code are
+good examples of how to use <tt>s6dns_engine</tt>.
+</p>
+
+<p>
+ However, unless you're implementing a DNS cache, you probably should
+not call the
+<tt>s6dns_engine</tt> functions directly: they are very low-level. If you
+need synchronous resolution, use the
+<a href="s6dns-resolve.html">s6dns_resolve</a> functions. If you need
+asynchronous DNS operations, use the
+<a href="../skadns/index.html">skadns</a> functions, which are
+designed to provide a higher level interface to multiple asynchronous
+DNS queries.
+</p>
+
+<h2> Data structures </h2>
+
+<p>
+ A <tt>s6dns_engine_t</tt> structure holds all the data necessary to
+manage a DNS query (and response). It must be initialized to S6DNS_ENGINE_ZERO
+when first declared, and recycled with <tt>s6dns_engine_recycle()</tt>
+after each use. It contains a stralloc, so it must be freed with
+<tt>s6dns_engine_free()</tt> before being discarded, to avoid memory leaks.
+</p>
+
+<h2> Functions </h2>
+
+<h3> <tt>s6dns_engine_t</tt> life cycle </h3>
+
+<p>
+<code> int s6dns_engine_init (s6dns_engine_t *dt, s6dns_ip46list_t const *servers, uint32 options, char const *q, unsigned int qlen, uint16 qtype, struct taia const *deadline, struct taia const *stamp) </code>
+</p>
+
+<p>
+Initializes <em>dt</em> with query <em>q</em> of length <em>qlen</em>
+and type <em>qtype</em>. If <tt>d</tt> is an
+encoded <tt>s6dns_domain_t</tt>, then <tt>d.s</tt> and <tt>d.len</tt>
+are appropriate candidates for arguments <em>q</em> and <em>qlen</em>
+respectively.
+</p>
+
+<p>
+<em>options</em> can be 0 or an OR'ed
+combination of the following, defined in <tt>s6-dns/s6dns-constants.h</tt>:
+</p>
+
+<ul>
+ <li> S6DNS_O_RECURSIVE: the query will be recursive and assuming it is
+sent to a DNS cache, instead of iterative and assuming it is sent to a
+DNS server. </li>
+ <li> S6DNS_O_STRICT: the library will only accept authoritative answers
+to iterative queries. This is normally the sane behaviour, but badly
+configured DNS software around the world - notably, <a href="../bind.html">
+BIND</a> when it's configured to be both a cache and a server - often
+serve <em>non-</em>authoritative data even when they could, so it
+breaks things, hence why the option isn't set by default. </li>
+</ul>
+
+<p>
+<em>servers</em> must point to a list of IP addresses as defined in
+<a href="s6dns-ip46.html">s6-dns/s6dns-ip46.h</a>. Such a list can be
+obtained from the <tt>/etc/resolv.conf</tt> file via the
+<a href="s6dns-rci.html">s6dns_rci_fill()</a> call when performing a
+recursive query, or it must be constructed from a list of relevant
+NS addresses when performing an iterative query.
+</p>
+
+<p>
+<em>stamp</em> must be an accurate enough timestamp. <em>deadline</em>
+sets up a deadline for the query: if the query hasn't been
+satisfactorily answered by <em>deadline</em> - no matter how many
+round-trips to network servers the library performs internally - then
+it will be considered failed, and a timeout will be reported.
+</p>
+
+<p>
+The function returns 1 if all went well, and 0 if an error occurred.
+It returns instantly; it <em>does not</em> perform any network operation,
+it just prepares <em>dt</em> to send a query. The actual data sending
+will take place on the next <tt>s6dns_engine_event()</tt> call.
+</p>
+
+<p>
+<code> void s6dns_engine_recycle (s6dns_engine_t *dt) </code>
+</p>
+
+<p>
+Recycles <tt>dt</tt>, making it ready for another use. This function
+does not deallocate the heap memory used by dt, so it's faster than
+<tt>s6dns_engine_free()</tt> and does not cause heap fragmentation.
+</p>
+
+<p>
+<code> void s6dns_engine_free (s6dns_engine_t *dt) </code>
+</p>
+
+<p>
+Frees the heap memory used by <tt>dt</tt>. Also makes <tt>dt</tt>
+ready for another use. It's advised to only use this function when
+certain that <em>dt</em> will not be reused.
+</p>
+
+<h3> Before the <tt>iopause()</tt> </h3>
+
+<p>
+ The descriptor to select on is available as the <tt>fd</tt> field in
+the <tt>s6dns_engine_t</tt> structure.
+<em>dt</em>&rarr;fd should be read every iteration, because it can
+change between iterations even if no event or timeout is reported
+for <em>dt</em>.
+</p>
+
+<p>
+<code> void s6dns_engine_nextdeadline (s6dns_engine_t const *dt, struct taia *a) </code>
+</p>
+
+<p>
+If <em>dt</em> needs handling before the absolute date *<em>a</em>,
+then *<em>a</em> is updated
+so it contains the earlier date. This is useful to compute the next
+deadline in an <tt>iopause()</tt> loop.
+</p>
+
+<p>
+<code> int s6dns_engine_isreadable (s6dns_engine_t const *dt) </code>
+</p>
+
+<p>
+Returns nonzero iff <em>dt</em>&rarr;fd is to be selected for reading.
+Should be called in every iteration.
+</p>
+
+<p>
+<code> int s6dns_engine_iswritable (s6dns_engine_t const *dt) </code>
+</p>
+
+<p>
+Returns nonzero iff <em>dt</em>&rarr;fd is to be selected for writing.
+Should be called in every iteration.
+</p>
+
+<h3> After the <tt>iopause()</tt> </h3>
+
+<p>
+<code> int s6dns_engine_timeout (s6dns_engine_t *dt, struct taia const *stamp) </code>
+</p>
+
+<p>
+This function should be called if your selecting function returned 0, which
+means that an event timed out.
+<em>stamp</em> should contain the current time. The function returns -1 if
+an error occurred, 1 if <em>dt</em> actually timed out, and 0 if nothing
+special happened to <em>dt</em> (and your iopause timeout was caused by
+something else). If the return value is not 0, <em>dt</em> is automatically
+recycled.
+</p>
+
+<p>
+<code> int s6dns_engine_event (s6dns_engine_t *dt, struct taia const *stamp) </code>
+</p>
+
+<p>
+This function should be called if your selecting function returned a positive
+number, which means that some event got triggered.
+<em>stamp</em> should contain the current time. The function returns
+-1 if an error occurred (and <em>dt</em> is automatically recycled). It
+returns 0 if no answer has arrived yet, and 1 if an answer is available.
+</p>
+
+<p>
+The <tt>s6dns_engine_timeout()</tt> and <tt>s6dns_engine_event()</tt> functions,
+when returning -1, make use of the following error codes:
+</p>
+<ul>
+ <li> EINVAL: Invalid <em>dt</em>.
+ <li> ENETUNREACH: All the servers in the <em>servers</em> list have been
+unsuccessfully tried. </li>
+ <li> EPROTO: An answer arrived, but it didn't follow the DNS protocol. </li>
+ <li> Other error codes reporting socket or system failures. </li>
+</ul>
+
+<p>
+<code> char *s6dns_engine_packet (s6dns_engine_t const *dt) </code>
+</p>
+
+<p>
+Points to the response packet received from the network,
+if <tt>s6dns_engine_event()</tt> returned 1.
+</p>
+
+<p>
+<code> unsigned int s6dns_engine_packetlen (s6dns_engine_t const *dt) </code>
+</p>
+
+<p>
+Gives the length of the response packet,
+if <tt>s6dns_engine_event()</tt> returned 1.
+</p>
+
+<p>
+ You should recycle or free <em>dt</em> after reading the response packet.
+</p>
+
+</body>
+</html>
diff --git a/doc/libs6dns/s6dns-fmt.html b/doc/libs6dns/s6dns-fmt.html
new file mode 100644
index 0000000..a586846
--- /dev/null
+++ b/doc/libs6dns/s6dns-fmt.html
@@ -0,0 +1,92 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6-dns: the s6dns_fmt library interface</title>
+ <meta name="Description" content="s6-dns: the s6dns_fmt library interface" />
+ <meta name="Keywords" content="s6-dns dns s6dns_fmt library libs6dns" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libs6dns</a><br />
+<a href="../">s6-dns</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>s6dns_fmt</tt> library interface </h1>
+
+<p>
+ The following functions and structures are declared in the <tt>s6-dns/s6dns-fmt.h</tt> header,
+and implemented in the <tt>libs6dns.a</tt> or <tt>libs6dns.so</tt> library.
+</p>
+
+<h2> General information </h2>
+
+<p>
+ <tt>s6dns_fmt</tt> provides primitives to format RR contents into
+printable strings.
+</p>
+
+<h2> Functions </h2>
+
+<p>
+<code> unsigned int s6dns_fmt_domain (char *s, unsigned int max, s6dns_domain_t const *d) </code> <br />
+Writes into string <em>s</em> the domain contained in *<em>d</em> (in string
+form). Returns the number of bytes written, or 0 in case of failure. If
+the output would be more than <em>max</em> bytes, 0 ENAMETOOLONG is returned.
+To avoid that, S6DNS_FMT_DOMAIN is a suitable number of bytes to preallocate <em>s</em>.
+This function is actually an alias to <tt>s6dns_domain_tostring</tt>.
+</p>
+
+<p>
+<code> unsigned int s6dns_fmt_domainlist (char *s, unsigned int max, s6dns_domain_t const *list, unsigned int n, char const *delin, unsigned int delimlen) </code> <br />
+Writes into string <em>s</em> the list of <em>n</em> domains (in string form)
+pointed to by <em>list</em>. Between each domain (and not after the last one),
+string <em>delim</em> of length <em>delimlen</em> is appended.
+The function returns the number of bytes written, or 0 in case of failure. If
+the output would be more than <em>max</em> bytes, 0 ENAMETOOLONG is returned.
+To avoid that, S6DNS_FMT_DOMAINLIST(n) is a suitable number of bytes to preallocate <em>s</em>.
+</p>
+
+<p>
+<code> unsigned int s6dns_fmt_hinfo (char *s, unsigned int max, s6dns_message_rr_hinfo_t const *p) </code> <br />
+Writes into string <em>s</em> the HINFO contained in *<em>p</em>: cpu, then os,
+separated by a space.
+Returns the number of bytes written, or 0 in case of failure. If
+the output would be more than <em>max</em> bytes, 0 ENAMETOOLONG is returned.
+To avoid that, S6DNS_FMT_HINFO is a suitable number of bytes to preallocate <em>s</em>.
+</p>
+
+<p>
+<code> unsigned int s6dns_fmt_mx (char *s, unsigned int max, s6dns_message_rr_mx_t const *p) </code> <br />
+Writes into string <em>s</em> the MX contained in *<em>p</em>: preference, then
+exchanger name, separated by a space.
+Returns the number of bytes written, or 0 in case of failure. If
+the output would be more than <em>max</em> bytes, 0 ENAMETOOLONG is returned.
+To avoid that, S6DNS_FMT_MX is a suitable number of bytes to preallocate <em>s</em>.
+</p>
+
+<p>
+<code> unsigned int s6dns_fmt_soa (char *s, unsigned int max, s6dns_message_rr_soa_t const *p) </code> <br />
+Writes into string <em>s</em> the SOA contained in *<em>p</em>:
+mname, then rname, then serial number, refresh time, retry time, expiration time
+and minimum time, separated by spaces.
+Returns the number of bytes written, or 0 in case of failure. If
+the output would be more than <em>max</em> bytes, 0 ENAMETOOLONG is returned.
+To avoid that, S6DNS_FMT_SOA is a suitable number of bytes to preallocate <em>s</em>.
+</p>
+
+<p>
+<code> unsigned int s6dns_fmt_srv (char *s, unsigned int max, s6dns_message_rr_srv_t const *p) </code> <br />
+Writes into string <em>s</em> the SRV contained in *<em>p</em>: priority,
+then weight, then port, then target, separated by spaces.
+Returns the number of bytes written, or 0 in case of failure. If
+the output would be more than <em>max</em> bytes, 0 ENAMETOOLONG is returned.
+To avoid that, S6DNS_FMT_SRV is a suitable number of bytes to preallocate <em>s</em>.
+</p>
+
+</body>
+</html>
diff --git a/doc/libs6dns/s6dns-ip46.html b/doc/libs6dns/s6dns-ip46.html
new file mode 100644
index 0000000..27cbe2c
--- /dev/null
+++ b/doc/libs6dns/s6dns-ip46.html
@@ -0,0 +1,69 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6-dns: the s6dns_ip46 library interface</title>
+ <meta name="Description" content="s6-dns: the s6dns_ip46 library interface" />
+ <meta name="Keywords" content="s6-dns dns s6dns_ip46 library libs6dns" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libs6dns</a><br />
+<a href="../">s6-dns</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>s6dns_ip46</tt> library interface </h1>
+
+<p>
+ The following functions are declared in the <tt>s6-dns/s6dns-ip46.h</tt> header,
+and implemented as macros.
+</p>
+
+<h2> General information </h2>
+
+<p>
+ <tt>s6dns_ip46</tt> is the transport abstraction layer. It allows
+the functions declared in <a href="s6dns-engine.html">s6-dns/s6dns-engine.h</a>
+and <a href="s6dns-rci.html">s6-dns/s6dns-rci.h</a> to be transport-agnostic,
+i.e. to be able to work with both IPv4 and IPv6.
+</p>
+
+<p>
+ If the underlying <a href="http://skarnet.org/software/skalibs/">skalibs</a>
+has been compiled with
+ <a href="http://skarnet.org/software/skalibs/flags.html#noipv6">flag-noipv6</a>,
+or if it has detected at build time that the target host does not support
+IPv6, then the s6dns-ip46 abstraction will be totally transparent and use
+no resources at all.
+</p>
+
+<h2> Data structures </h2>
+
+<p>
+ A <tt>s6dns_ip46list_t</tt> structure holds a list of S6DNS_MAX_SERVERS (16)
+IPv4 <em>or</em> IPv6 addresses. Such a mixed list can be constructed, for
+instance, if the <tt>/etc/resolv.conf</tt> file contains both v4 and v6
+<tt>nameserver</tt> lines.
+</p>
+
+<h2> Functions </h2>
+
+<p>
+ If <em>list</em> is a <tt>s6dns_ip46list_t</tt> and <em>i</em> an integer
+between 0 and DNS_MAX_SERVERS-1, then
+</p>
+
+<ul>
+ <li> <code>s6dns_ip46list_is6(&amp;list, i)</code> is 1 if the <em>i</em>th
+address in <em>list</em> is IPv6 and 0 if it is IPv4. </li>
+ <li> <code>s6dns_ip46list_ip(&amp;list, i)</code> is a <tt>char *</tt> pointer to
+16 (if IPv6) or 4 (IPv4) bytes representing the <em>i</em>th address in
+<em>list</em>, in network byte order. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/libs6dns/s6dns-message.html b/doc/libs6dns/s6dns-message.html
new file mode 100644
index 0000000..e06aa91
--- /dev/null
+++ b/doc/libs6dns/s6dns-message.html
@@ -0,0 +1,261 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6-dns: the s6dns_message library interface</title>
+ <meta name="Description" content="s6-dns: the s6dns_message library interface" />
+ <meta name="Keywords" content="s6-dns dns s6dns_message library libs6dns" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libs6dns</a><br />
+<a href="../">s6-dns</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>s6dns_message</tt> library interface </h1>
+
+<p>
+ The following functions are declared in the <tt>s6-dns/s6dns-message.h</tt> header,
+and implemented in the <tt>libs6dns.a</tt> or <tt>libs6dns.so</tt> library.
+</p>
+
+<h2> General information </h2>
+
+<p>
+ <tt>s6dns_message</tt> provides functions to read and parse DNS messages
+sent by servers and caches and containing answers to queries.
+</p>
+
+<h2> Data structures </h2>
+
+<p>
+ A <tt>s6dns_message_header_t</tt> is a structure containing the header
+of a received DNS packet, broken down for easy access to the bits.
+</p>
+
+<p>
+ A <tt>s6dns_message_rr_t</tt> is a structure containing the information
+about a resource record given by an answer packet - all of it, except the
+value of the answer itself, which is rtype-specific and has to be decoded
+by rtype-specific functions.
+</p>
+
+<p>
+ A <tt>s6dns_message_rr_func_t</tt> is the type of such a function. The
+prototype is <br />
+<code> int f (s6dns_message_rr_t const *rr, char const *packet, unsigned int packetlen, unsigned int pos, unsigned int section, void *data) </code> <br />
+</p>
+
+<ul>
+ <li> *<em>rr</em> contains the header information of the resource record,
+including the domain to which it applies, the rtype, and the ttl. </li>
+ <li> <em>packet</em> points to the <strong>whole DNS packet</strong> the RR
+is a part of. </li>
+ <li> <em>packetlen</em> is the total length of said packet. </li>
+ <li> <em>pos</em> is the offset of the RR in the DNS packet, i.e. <em>f</em>
+should start parsing at <em>packet + pos</em>. </li>
+ <li> <em>section</em> is the section the RR belongs to: 2 for answer, 3 for
+authority, 4 for additional. </li>
+ <li> <em>data</em> is a user-specified pointer; it is typically used to
+write the decoded output, in a rtype-specific way. </li>
+ <li> <em>f</em> must return 1 or more if it succeeds in decoding the packet.
+Else it must set errno appropriately, and return -1 if the error is local,
+unrelated to the packet - for instance, it has run out of memory - or 0 if it
+cannot decode the RR because of the packet contents. </li>
+</ul>
+
+<p>
+ Various structures designed to store specific resource record types are
+also provided. The list includes:
+</p>
+
+<ul>
+ <li> <tt>s6dns_message_rr_hinfo</tt> for HINFO RRs </li>
+ <li> <tt>s6dns_message_rr_mx</tt> for MX RRs </li>
+ <li> <tt>s6dns_message_rr_soa</tt> for SOA RRs </li>
+ <li> <tt>s6dns_message_rr_srv</tt> for SRV RRs </li>
+</ul>
+
+<h2> Functions </h2>
+
+<h3> Header management </h3>
+
+<p>
+<code> void s6dns_message_header_pack (char *s, s6dns_message_header_t const *h) </code> <br />
+Packs the header *<em>h</em> into the 12 bytes pointed to by <em>s</em>.
+</p>
+
+<p>
+<code> void s6dns_message_header_unpack (char const *s, s6dns_message_header_t *h) </code> <br />
+Unpacks the 12 bytes pointed to by <em>s</em> into the structure *<em>h</em>.
+</p>
+
+<h3> Low-level RR decoding </h3>
+
+<p>
+ The following primitives are used in the implementation of
+<tt>s6dns_message_rr_func_t</tt>-typed functions, to read and decode information
+stored in a DNS packet. Their arguments are:
+</p>
+
+<ol>
+ <li> A pointer to the structure where the information is going to be stored </li>
+ <li> A read-only pointer to the beginning of the DNS packet </li>
+ <li> The length of the DNS packet </li>
+ <li> A pointer to an integer containing the current position in the
+DNS packet, i.e. where the information is going to be read. If the functions
+succeed, they automatically update the position so information can be read
+sequentially. </li>
+</ol>
+
+<p>
+<code> int s6dns_message_get_string (s6dns_domain_t *d, char const *packet, unsigned int packetlen, unsigned int *pos) </code> <br />
+Reads a character-string and stores it into *<em>d</em>. Returns 1 on success
+and 0 on failure. Note that *<em>d</em> does not contain a domain, but the
+<tt>s6dns_domain_t</tt> structure is adapted to store strings that do not
+exceed 255 characters. <em>d</em>&rarr;s can be used to access the string,
+and <em>d</em>&rarr;len its length.
+</p>
+
+<p>
+<code> int s6dns_message_get_strings (char *s, unsigned int rdlength, char const *packet, unsigned int packetlen, unsigned int *pos </code> <br />
+This function takes an additional parameter <em>rdlength</em>. It reads a series of
+character-strings and stores their concatenation into the string <em>s</em>, which
+must be preallocated; it can never store more than <em>rdlength</em> bytes. It returns
+-1 if it fails; on success, it returns the number of bytes written. The
+<em>rdlength</em> parameter must be the length of the resource record containing
+the series of character-strings.
+</p>
+
+<p>
+<code> unsigned int s6dns_message_get_domain (s6dns_domain_t *d, char const *packet, unsigned int packetlen, unsigned int *pos) </code> <br />
+Reads a domain and stores it, in string form, into *<em>d</em>.
+Returns 1 on success and 0 on failure, and sets errno:
+</p>
+
+<ul>
+ <li> EPROTO: there is no proper domain to be read in position *<em>pos</em> of
+<em>packet</em>. Either the packet is malformed or the function is being
+misused. </li>
+ <li> EPROTONOSUPPORT: the domain encoding uses an extension that the function
+does not recognize. </li>
+</ul>
+
+<p>
+<code> int s6dns_message_get_hinfo (s6dns_message_rr_hinfo_t *p, char const *packet, unsigned int packetlen, unsigned int *pos) </code> <br />
+Reads a HINFO RR and stores it into *<em>p</em>. Returns 1 on success or 0
+on failure.
+</p>
+
+<p>
+<code> int s6dns_message_get_mx (s6dns_message_rr_mx_t *p, char const *packet, unsigned int packetlen, unsigned int *pos) </code> <br />
+Reads a MX RR and stores it into *<em>p</em>. Returns 1 on success or 0 on failure.
+</p>
+
+<p>
+<code> int s6dns_message_get_soa (s6dns_message_rr_soa_t *p, char const *packet, unsigned int packetlen, unsigned int *pos) </code> <br />
+Reads a SOA RR and stores it into *<em>p</em>. Returns 1 on success or 0 on failure.
+</p>
+
+<p>
+<code> int s6dns_message_get_srv (s6dns_message_rr_srv_t *p, char const *packet, unsigned int packetlen, unsigned int *pos) </code> <br />
+Reads a SRV RR and stores it into *<em>p</em>. Returns 1 on success or 0 on failure.
+</p>
+
+<h3> High-level RR-specific parsing functions </h3>
+
+<p>
+<code> s6dns_message_func_t s6dns_message_parse_answer_strings </code> <br />
+Parses character-strings located in the answer section of the packet. The
+<em>data</em> argument is interpreted as a pointer to a <tt>s6dns_mpag_t</tt>,
+which is a structure defined in the <tt>s6-dns/s6dns-message.h</tt> header
+and used to store multiple character-strings.
+</p>
+
+<p>
+<code> s6dns_message_func_t s6dns_message_parse_answer_domain </code> <br />
+Parses domains located in the answer section of the packet. The
+<em>data</em> argument is interpreted as a pointer to a <tt>s6dns_dpag_t</tt>,
+which is a structure defined in the <tt>s6-dns/s6dns-message.h</tt> header
+and used to store multiple domains.
+</p>
+
+<p>
+<code> s6dns_message_func_t s6dns_message_parse_answer_a </code> <br />
+Parses A RRs located in the answer section of the packet. The
+<em>data</em> argument is interpreted as a pointer to a
+<a href="http://skarnet.org/software/skalibs/libstddjb/stralloc.html">stralloc</a>,
+and 4 bytes are appended to this stralloc for every IPv4 address found.
+</p>
+
+
+<code> s6dns_message_func_t s6dns_message_parse_answer_aaaa </code> <br />
+Parses AAAA RRs located in the answer section of the packet. The
+<em>data</em> argument is interpreted as a pointer to a
+<a href="http://skarnet.org/software/skalibs/libstddjb/stralloc.html">stralloc</a>,
+and 16 bytes are appended to this stralloc for every IPv6 address found.
+</p>
+
+<p>
+<code> s6dns_message_func_t s6dns_message_parse_answer_hinfo </code> <br />
+Parses HINFO RRs located in the answer section of the packet. The
+<em>data</em> argument is interpreted as a pointer to a
+<a href="http://skarnet.org/software/skalibs/libstddjb/genalloc.html">genalloc</a>
+containing <tt>s6dns_message_rr_hinfo_t</tt> structures.
+</p>
+
+<p>
+<code> s6dns_message_func_t s6dns_message_parse_answer_mx </code> <br />
+Parses MX RRs located in the answer section of the packet. The
+<em>data</em> argument is interpreted as a pointer to a
+<a href="http://skarnet.org/software/skalibs/libstddjb/genalloc.html">genalloc</a>
+containing <tt>s6dns_message_rr_mx_t</tt> structures.
+</p>
+
+<p>
+<code> s6dns_message_func_t s6dns_message_parse_answer_soa </code> <br />
+Parses SOA RRs located in the answer section of the packet. The
+<em>data</em> argument is interpreted as a pointer to a
+<a href="http://skarnet.org/software/skalibs/libstddjb/genalloc.html">genalloc</a>
+containing <tt>s6dns_message_rr_soa_t</tt> structures.
+</p>
+
+<p>
+<code> s6dns_message_func_t s6dns_message_parse_answer_srv </code> <br />
+Parses SRV RRs located in the answer section of the packet. The
+<em>data</em> argument is interpreted as a pointer to a
+<a href="http://skarnet.org/software/skalibs/libstddjb/genalloc.html">genalloc</a>
+containing <tt>s6dns_message_rr_srv_t</tt> structures.
+</p>
+
+<h3> High-level packet parsing </h3>
+
+<p>
+<code> int s6dns_message_parse (s6dns_message_header_t *h, char const *packet, unsigned int packetlen, s6dns_message_rr_func_t *f, void *data) </code> <br />
+ This function parses the DNS packet <em>packet</em> of length <em>packetlen</em>.
+It stores the packet header into *<em>h</em>. Then, for every RR in the answer,
+authority or additional section of the packet, it calls <em>f</em> with the
+relevant parameters. <em>data</em> is the extra pointer given to <em>f</em> to
+store information. The function returns 1 if the parsing succeeds. Otherwise it
+returns -1 if there is a local error unrelated to the packet, or 0 if no
+appropriate answer can be decoded from the packet. errno then contains one
+of the following values:
+</p>
+
+<ul>
+ <li> EPROTO: the packet is malformed, syntax error </li>
+ <li> EBADMSG: rcode 1, query format error </li>
+ <li> EBUSY: rcode 2, server failure </li>
+ <li> ENOENT: rcode 3, nxdomain </li>
+ <li> ENOTSUP: rcode 4, query type not implemented </li>
+ <li> ECONNREFUSED: rcode 5, operation refused by server </li>
+ <li> EIO: unknown rcode </li>
+ <li> any other value being set by <em>f</em> if it returns a failure code. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/libs6dns/s6dns-rci.html b/doc/libs6dns/s6dns-rci.html
new file mode 100644
index 0000000..1cf8a0e
--- /dev/null
+++ b/doc/libs6dns/s6dns-rci.html
@@ -0,0 +1,109 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6-dns: the s6dns_rci library interface</title>
+ <meta name="Description" content="s6-dns: the s6dns_rci library interface" />
+ <meta name="Keywords" content="s6-dns dns s6dns_rci resolv.conf library libs6dns" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libs6dns</a><br />
+<a href="../">s6-dns</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>s6dns_rci</tt> library interface </h1>
+
+<p>
+ The following functions and structures are declared in the <tt>s6-dns/s6dns-rci.h</tt> header,
+and implemented in the <tt>libs6dns.a</tt> or <tt>libs6dns.so</tt> library.
+</p>
+
+<h2> General information </h2>
+
+<p>
+ <tt>s6dns_rci</tt> provides functions to get information from
+the <tt>/etc/resolv.conf</tt> file.
+</p>
+
+<h2> Data structures </h2>
+
+<p>
+ A <tt>s6dns_rci_t</tt> is a structure storing information
+provided by the <tt>/etc/resolv.conf</tt> file, i.e.
+</p>
+
+<ul>
+ <li> The list of "nameserver" addresses, i.e. IP addresses of DNS caches
+contacted by clients for recursive queries </li>
+ <li> The list of qualification rules provided by "domain" or "search"
+lines </li>
+</ul>
+
+<p>
+ Nameserver addresses are stored in a
+<a href="s6dns-ip46.html">s6dns_ip46list_t</a>. Qualification rules are
+stored in a <a href="http://skarnet.org/software/skalibs/libstddjb/stralloc.html">stralloc</a>
+with an additional integer storing the number of rules.
+</p>
+
+<p>
+ Most programs won't need more than one <tt>s6dns_rci_t</tt>, so
+the library provides the global variable <tt>s6dns_rci_here</tt>, used
+by default in simple resolution macros.
+</p>
+
+<h2> Functions </h2>
+
+<p>
+<code> int s6dns_rci_init (s6dns_rci_t *rci, char const *file) </code> <br />
+Extracts information from <em>file</em>, which must be in <tt>/etc/resolv.conf</tt>
+format, and stores it into *<em>rci</em>. <em>rci</em> must be previously
+initialized to the <tt>S6DNS_RCI_ZERO</tt> constant. The function returns 1 if
+it succeeds, or 0 (and sets errno) if it fails.
+</p>
+
+<p>
+ If the DNSCACHEIP environment variable is set, and contains a list of
+IP addresses separated by commas, semicolons, spaces, tabs, newlines or
+carriage returns, then this list overrides any nameserver information
+from <em>file</em>. If the variable is empty, <em>file</em> will be used
+as the source of the information.
+</p>
+
+<p>
+ If the DNSQUALIFY environment variable is set, a list of domain suffixes,
+separated by spaces, tabs, newlines or carriage returns, is read from it,
+and overrides any qualification information from <em>file</em>. If the
+variable is empty, it amounts to one rule saying "no qualification".
+</p>
+
+<p>
+ <tt>s6dns_init()</tt> is an alias to
+<tt>s6dns_rci_init(&amp;s6dns_rci_here, "/etc/resolv.conf")</tt>.
+</p>
+
+<p>
+<code> void s6dns_rci_free (s6dns_rci_t *rci) </code> <br />
+Frees the memory used by *<em>rci</em>. <em>rci</em> is then suitable to
+be reused in a <tt>s6dns_rci_init</tt> call.
+</p>
+
+<p>
+ <tt>s6dns_finish()</tt> calls <tt>s6dns_rci_free(&amp;s6dns_rci_here)</tt>.
+</p>
+
+<p>
+<code> unsigned int s6dns_qualify (s6dns_domain_t *list, s6dns_domain_t const *d) </code> <br />
+Qualifies domain *<em>d</em> into the list of domains pointed to by <em>list</em>
+according to the rules stored in <tt>s6dns_rci_here</tt>. Returns the number of
+written domains (0 if it fails); this number cannot exceed
+<tt>s6dns_rci_here.rulesnum</tt>.
+</p>
+
+</body>
+</html>
diff --git a/doc/libs6dns/s6dns-resolve.html b/doc/libs6dns/s6dns-resolve.html
new file mode 100644
index 0000000..bbb3f57
--- /dev/null
+++ b/doc/libs6dns/s6dns-resolve.html
@@ -0,0 +1,387 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6-dns: the s6dns_resolve library interface</title>
+ <meta name="Description" content="s6-dns: the s6dns_resolve library interface" />
+ <meta name="Keywords" content="s6-dns dns s6dns_resolve library libs6dns" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libs6dns</a><br />
+<a href="../">s6-dns</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>s6dns_resolve</tt> library interface </h1>
+
+<p>
+ The following functions are declared in the <tt>s6-dns/s6dns-resolve.h</tt> header,
+and implemented in the <tt>libs6dns.a</tt> or <tt>libs6dns.so</tt> library.
+</p>
+
+<h2> General information </h2>
+
+<p>
+ <tt>s6dns_resolve</tt> provides functions and macros - mostly macros -
+to perform high level synchronous DNS resolution.
+</p>
+
+<p>
+ All the functions declared here make synchronous calls to the network, so
+they can block for a non-negligible amount of time. To avoid unbounded
+waiting times, they always take 2 arguments at the end, <em>deadline</em>
+and <em>stamp</em>. <em>deadline</em> is the read-only address of a
+<a href="http://skarnet.org/software/skalibs/libstddjb/tai.h">struct taia</a>
+containing an absolute time which is the deadline for the function, and
+<em>stamp</em> is the read-write address of a <tt>struct taia</tt> being
+an accurate enough representation of the current absolute time. If
+the function has not returned by *<em>deadline</em>, then it immediately
+returns with a failure code and errno set to ETIMEDOUT. In every case,
+*<em>stamp</em> is automatically updated so it always represents the
+absolute time accurately enough.
+</p>
+
+<p>
+ In a single-threaded program, the STAMP global variable can be used to
+store the current time. Macros ending with <tt>_g</tt> use this variable
+automatically so you don't have to provide the <em>stamp</em> argument
+everytime. Additionally, several resolution functions make implicit use
+of global variables such as:
+</p>
+
+<ul>
+ <li> <tt>s6dns_engine_here</tt>: a global
+<a href="s6dns-engine.html">s6dns_engine_t</a> storing the current
+query, for sequential queries. </li>
+ <li> <tt>s6dns_debughook_zero</tt>: a global <tt>s6dns_debughook_t</tt>
+meaning no debugging is needed. </li>
+ <li> <tt>s6dns_rci_here</tt>: a global
+<a href="s6dns-rci.html">s6dns_rci_t</a> containing the current
+resolv.conf information. </li>
+</ul>
+
+<p>
+ Reentrant, non-global-using functions are also provided, with the <tt>_r</tt>
+suffix. In other words, if <em>foobarfunc</em> is a resolution function,
+the following prototypes are generally provided, from the simplest to the
+most complex:
+</p>
+
+<ul>
+ <li> <em>foobarfunc_g</em>: only the relevant parameters and a deadline
+must be given, the function uses the STAMP global and maybe DNS-specific
+globals </li>
+ <li> <em>foobarfunc</em>: a deadline and stamp must be given, the function
+uses all the DNS-specific globals </li>
+ <li> <em>foobarfunc_r_g</em>: No DNS-specific globals are used, the
+information must be given via parameters, but the STAMP global is used </li>
+ <li> <em>foobarfunc_r</em>: fully reentrant function using no globals
+at all </li>
+</ul>
+
+<p>
+ For each set of four functions, only one is documented here.
+The other prototypes can be found in the <tt>s6-dns/s6dns-resolve.h</tt> file.
+</p>
+
+<p>
+ Some <tt>errno</tt> codes reported by these functions do not have
+exactly the system meaning given by
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/strerror.html">strerror()</a>.
+To get a user-friendly error message, use
+<tt>s6dns_constants_error_str(errno)</tt> instead. The <tt>s6dns_constants_error_str</tt>
+function is declared in the <tt>s6dns-constants.h</tt> header.
+</p>
+
+<h2> Functions </h2>
+
+<h3> Single query resolution </h3>
+
+<p>
+ These functions are ordered from the lowest level to the highest level.
+</p>
+
+<h4> Basic wrapper around s6dns_engine </h4>
+
+<p>
+<code> int s6dns_resolve_loop_r_g (s6dns_engine_t *dt, struct taia const *deadline) </code> <br />
+Resolves the query stored in <tt>dt</tt>.
+Returns 1 on success or 0 on failure.
+</p>
+
+<h4> Generic resolution functions </h4>
+
+<p>
+<code> int s6dns_resolve_core_g (s6dns_domain_t const *d, uint16 qtype, struct taia const *deadline) </code> <br />
+Resolves the query on domain *<em>d</em> (in packet form), of type <em>qtype</em>.
+Returns 0 on failure, or 1 on success, in which case
+<tt>s6dns_engine_here</tt> contains the answer.
+</p>
+
+<p>
+<code> int s6dns_resolve_parse_g (s6dns_domain_t const *d, uint16 qtype, s6dns_message_rr_func_t *f, void *data, struct taia const *deadline) </code> <br />
+Resolves the query on domain *<em>d</em> (in packet form), of type <em>qtype</em>,
+then parses the answer with function <em>f</em> and stores the result into <em>data</em>.
+Returns 1 if it succeeds, 0 if no data can be extracted from the answer, or -1 if an
+error occurs. Sets errno in the last two cases.
+</p>
+
+<p>
+ Note that the function can return 1 without appending anything to <em>data</em>.
+This means that the servers confirmed that the domain exists, but <em>f</em>
+has not been able to find any data relevant to the query in the answer.
+This is very different from NXDOMAIN, which means that
+the servers deny the actual existence of the domain, and which is reported
+here as a return code of 0 with errno set to ENOENT.
+</p>
+
+<p>
+<code> int s6dns_resolvenoq_g (char const *name, unsigned int len, uint16 qtype, s6dns_message_rr_func_t *f, void *data, struct taia const *deadline) </code> <br />
+Performs a query of type <em>qtype</em> on name <em>name</em> of length <em>len</em>,
+without qualifying it. Parses the answer with function <em>f</em> and stores the
+result into <em>data</em>. Returns 1 if it succeeds, 0 if no data can be extracted,
+or -1 if an error occurs. Sets errno in the last two cases.
+</p>
+
+<p>
+<code> int s6dns_resolveq_g (char const *name, unsigned int len, uint16 qtype, s6dns_message_rr_func_t *f, void *data, struct taia const *deadline) </code> <br />
+Performs a query of type <em>qtype</em> on name <em>name</em> of length <em>len</em>,
+qualifying it first. Parses the answer with function <em>f</em> and stores the
+result into <em>data</em>. Returns 1 if it succeeds, 0 if none of the FQDNs can
+get a positive answer, or -1 if an error occurs. Sets errno in the last two cases.
+</p>
+
+<p>
+<code> int s6dns_resolve_g (char const *name, unsigned int len, uint16 qtype, s6dns_message_rr_func_t *f, void *data, int qualif, struct taia const *deadline) </code> <br />
+Performs a query of type <em>qtype</em> on name <em>name</em> of length <em>len</em>.
+Qualifies <em>name</em> first if <em>qualif</em> is nonzero; else, does not
+qualify it. Parses the answer with function <em>f</em> and stores the
+result into <em>data</em>. Returns 1 if it succeeds, 0 if none of the FQDNs can
+get a positive answer, or -1 if an error occurs. Sets errno in the last two cases.
+</p>
+
+<h4> High-level type-specific functions </h4>
+
+<p>
+<code> int s6dns_resolve_a_g (stralloc *ips, char const *name, unsigned int len, int qualif, struct taia const *deadline) </code> <br />
+Performs an A query on name <em>name</em> of length <em>len</em>, qualifying it
+iff <em>qualif</em> is nonzero. Returns -1 if an error occurs, or 0 if no answer
+can be obtained from servers, or 1 if it succeeds, in which case the IPs are
+appended to the stralloc *<em>ips</em>, using 4 bytes per answer.
+</p>
+
+<p>
+<code> int s6dns_resolve_aaaa_g (stralloc *ips, char const *name, unsigned int len, int qualif, struct taia const *deadline) </code> <br />
+Performs an AAAA query on name <em>name</em> of length <em>len</em>, qualifying it
+iff <em>qualif</em> is nonzero. Returns -1 if an error occurs, or 0 if no answer
+can be obtained from servers, or 1 if it succeeds, in which case the IPs are
+appended to the stralloc *<em>ips</em>, using 16 bytes per answer.
+</p>
+
+<p>
+<code> int s6dns_resolve_aaaaa_g (genalloc *ips, char const *name, unsigned int len, int qualif, struct taia const *deadline) </code> <br />
+Performs an AAAA query and an A query at the same time on name <em>name</em>
+of length <em>len</em>, qualifying it first iff <em>qualif</em> is nonzero.
+Returns -1 if an error occurs, or 0 if no answer
+can be obtained from servers, or a positive number if it succeeds: 1 if IPv4 addresses
+were found, 2 if IPv6 addresses were found, and 3 if both were found.
+The IPs are appended to the genalloc *<em>ips</em>, which contains an array of
+<tt>ip46_t</tt>, the skalibs structure used to store IPv4 and IPv6 addresses
+indiscriminately.
+</p>
+
+<p>
+<code> int s6dns_resolve_ptr_g (genalloc *ds, char const *name, unsigned int len, int qualif, struct taia const *deadline) </code> <br />
+Performs a PTR query on name <em>name</em> of length <em>len</em>, qualifying it
+iff <em>qualif</em> is nonzero. Returns -1 if an error occurs, or 0 if no answer
+can be obtained from servers, or 1 if it succeeds, in which case the domains are
+appended to the genalloc *<em>ds</em>, which contains an array of <tt>s6dns_domain_t</tt>.
+</p>
+
+<p>
+<code> int s6dns_resolve_name4_g (genalloc *ds, char const *ip, struct taia const *deadline) </code> <br />
+Performs a PTR query on the <tt>in-addr.arpa.</tt> name representing the IPv4
+address <em>ip</em> (4 network-order bytes).
+Returns -1 if an error occurs, or 0 if no answer
+can be obtained from servers, or 1 if it succeeds, in which case the domains are
+appended to the genalloc *<em>ds</em>, which contains an array of <tt>s6dns_domain_t</tt>.
+</p>
+
+<p>
+<code> int s6dns_resolve_name6_g (genalloc *ds, char const *ip, struct taia const *deadline) </code> <br />
+Performs a PTR query on the <tt>ip6.arpa.</tt> name representing the IPv6
+address <em>ip</em> (16 network-order bytes).
+Returns -1 if an error occurs, or 0 if no answer
+can be obtained from servers, or 1 if it succeeds, in which case the domains are
+appended to the genalloc *<em>ds</em>, which contains an array of <tt>s6dns_domain_t</tt>.
+</p>
+
+<p>
+<code> int s6dns_resolve_name46_g (genalloc *ds, ip46_t const *ip, struct taia const *deadline) </code> <br />
+Calls <tt>s6dns_resolve_name6_g()</tt> or <tt>s6dns_resolve_name4_g()</tt>
+depending on which <em>ip</em> is an IPv6 or IPv4 address.
+</p>
+
+<p>
+<code> int s6dns_resolve_ns_g (genalloc *ds, char const *name, unsigned int len, int qualif, struct taia const *deadline) </code> <br />
+Performs a NS query on name <em>name</em> of length <em>len</em>, qualifying it
+iff <em>qualif</em> is nonzero. Returns -1 if an error occurs, or 0 if no answer
+can be obtained from servers, or 1 if it succeeds, in which case the domains are
+appended to the genalloc *<em>ds</em>, which contains an array of <tt>s6dns_domain_t</tt>.
+</p>
+
+<p>
+<code> int s6dns_resolve_cname_g (genalloc *ds, char const *name, unsigned int len, int qualif, struct taia const *deadline) </code> <br />
+Performs a CNAME query on name <em>name</em> of length <em>len</em>, qualifying it
+iff <em>qualif</em> is nonzero. Returns -1 if an error occurs, or 0 if no answer
+can be obtained from servers, or 1 if it succeeds, in which case the domains are
+appended to the genalloc *<em>ds</em>, which contains an array of <tt>s6dns_domain_t</tt>.
+</p>
+
+<p>
+<code> int s6dns_resolve_hinfo_g (genalloc *hinfos, char const *name,
+unsigned int len, int qualif, struct taia const *deadline) </code> <br />
+ Performs an HINFO query on name <em>name</em> of length <em>len</em>, qualifying it
+iff <em>qualif</em> is nonzero. Returns -1 if an error occurs, or 0 if no answer
+can be obtained from servers, or 1 if it succeeds, in which case the domains are
+appended to the genalloc *<em>hinfos</em>, which contains an array of
+<tt>s6dns_message_rr_hinfo_t</tt>.
+</p>
+
+<p>
+<code> int s6dns_resolve_mx_g (genalloc *mxs, char const *name,
+unsigned int len, int qualif, struct taia const *deadline) </code> <br />
+ Performs an MX query on name <em>name</em> of length <em>len</em>, qualifying it
+iff <em>qualif</em> is nonzero. Returns -1 if an error occurs, or 0 if no answer
+can be obtained from servers, or 1 if it succeeds, in which case the domains are
+appended to the genalloc *<em>mxs</em>, which contains an array of
+<tt>s6dns_message_rr_mx_t</tt>.
+</p>
+
+<p>
+<code> int s6dns_resolve_soa_g (genalloc *soas, char const *name,
+unsigned int len, int qualif, struct taia const *deadline) </code> <br />
+ Performs an SOA query on name <em>name</em> of length <em>len</em>, qualifying it
+iff <em>qualif</em> is nonzero. Returns -1 if an error occurs, or 0 if no answer
+can be obtained from servers, or 1 if it succeeds, in which case the domains are
+appended to the genalloc *<em>soas</em>, which contains an array of
+<tt>s6dns_message_rr_soa_t</tt>.
+</p>
+
+<p>
+<code> int s6dns_resolve_srv_g (genalloc *srvs, char const *name,
+unsigned int len, int qualif, struct taia const *deadline) </code> <br />
+ Performs an SRV query on name <em>name</em> of length <em>len</em>, qualifying it
+iff <em>qualif</em> is nonzero. Returns -1 if an error occurs, or 0 if no answer
+can be obtained from servers, or 1 if it succeeds, in which case the domains are
+appended to the genalloc *<em>srvs</em>, which contains an array of
+<tt>s6dns_message_rr_srv_t</tt>.
+</p>
+
+<p>
+<code> int s6dns_resolve_txt_g (stralloc *sa, genalloc *offsets, char const *name,
+unsigned int len, int qualif, struct taia const *deadline) </code> <br />
+ Performs an TXT query on name <em>name</em> of length <em>len</em>, qualifying it
+iff <em>qualif</em> is nonzero. Returns -1 if an error occurs, or 0 if no answer
+can be obtained from servers, or 1 if it succeeds, in which case:
+</p>
+
+<ul>
+ <li> The resulting strings are all stored into stralloc *<em>sa</em>.
+Every string is terminated by a null character. </li>
+ <li> A series of unsigned ints is appended to genalloc *<em>offsets</em>.
+Every integer represents the offset in *<em>sa</em> at which a string is stored.
+The number of appended integers is the total number of answers. </li>
+</ul>
+
+<h4> Parallel resolution </h4>
+
+<p>
+<code> int s6dns_resolven_loop_g (s6dns_engine_t *dtl, unsigned int n,
+unsigned int or, struct taia const *deadline) </code> <br />
+ Resolves the <em>n</em> queries stored in the array pointed to by <em>dtl</em>,
+in parallel. If <em>or</em> is zero, it does not return before all answers
+have arrived. If <em>or</em> is 1, it returns when an answer arrives, but does
+not return if a query generates an error (unless all queries do so). If
+<em>or</em> is 2, it returns when an answer arrives or an error occurs.
+Other values of <em>or</em> are unspecified yet.
+
+<p>
+ The return code is as follows:
+</p>
+
+<ul>
+ <li> If <em>or</em> is 0: -1 on a global error (i.e. not specific to
+a query), or a non-negative number which is the total of successful
+queries. </li>
+ <li> If <em>or</em> is 1 or 2: -1 on a global error, or a non-negative
+number which is the index of the query that triggered the event. </li>
+</ul>
+
+<p>
+ If <em>or</em> is 1, a return code of -1 with errno set to ENOENT
+means that all the queries failed.
+</p>
+
+<p>
+ After the function returns, the <tt>status</tt> field of each
+<tt>s6dns_engine_t</tt> contains the error code relative to the query.
+A status of 0 means that an answer has properly arrived; EAGAIN means
+that the query is still pending (and the s6dns_engine_t has not been
+recycled); ECONNABORTED means that the query has not been properly
+initialized. Other codes report various network problems.
+</p>
+
+<p>
+<code> int s6dns_resolven_parse_g (s6dns_resolve_t const *list, unsigned int n,
+struct taia const *deadline) </code> <br />
+Performs <em>n</em> complete resolutions in parallel, parsing the results.
+Returns 1 in case of success or 0 if a global error occurred.
+</p>
+
+<p>
+<em>list</em> is a pointer to an array of <em>n</em> <tt>s6dns_resolve_t</tt>,
+which is a structure containing at least the following fields:
+</p>
+
+<ul>
+ <li> <tt>q</tt>&nbsp;: a <tt>s6dns_domain_t</tt> containing the query.
+It must be in encoded form. </li>
+ <li> <tt>qtype</tt>&nbsp;: a <tt>uint16</tt> containing the query type.
+A list of valid query types can be found in the <tt>s6dns-constants.h</tt>
+header. </li>
+ <li> <tt>options</tt>&nbsp;: a <tt>uint32</tt> containing options passed
+to <a href="s6dns_engine.html">s6dns_engine_init()</a>. </li>
+ <li> <tt>deadline</tt>&nbsp;: a <tt>struct taia</tt> containing the
+deadline for this query, i.e. the query will fail with an ETIMEDOUT code
+if no answer has arrived by then. Note that the <em>deadline</em>
+argument given to s6dns_resolven_parse() is a global deadline that
+can make the function return with 0 ETIMEDOUT, but is independent from
+this field, which is local to every query. </li>
+ <li> <tt>parsefunc</tt>&nbsp;: a <tt>s6dns_message_rr_func_t</tt>
+function that will be used to parse the answer. </li>
+ <li> <tt>data</tt>&nbsp;: a <tt>void *</tt> that will be passed as an
+additional pointer to the <tt>parsefunc</tt> function; it is generally
+used to store the parsing result. </li>
+ <li> <tt>status</tt>&nbsp;: an <tt>int</tt>. It does not need to be
+initialized. It will contain the error code for the query after the
+function returns. ECONNABORTED means that the query could not be
+started at all; EAGAIN means that the query was still pending when
+an error happened; other codes report various network problems. </li>
+</ul>
+
+<p>
+ The s6dns_resolven_parse() function is a simple, convenient way to
+perform several resolutions in parallel to avoid the waiting time
+incurred by serial resolutions. However, it is still a synchronous
+function, and cannot replace a real asynchronous DNS library: for
+more complex parallel resolution needs, use the
+<a href="../skadns/">skadns</a> library.
+</p>
+
+</body>
+</html>