ARES_SEND(3)

πŸ“¦
version 1.34.9 Β· 5 versions
, in alpine 3.22, alpine 3.23, alpine 3.24, arch rolling, centos-stream 10, fedora 43, fedora 44, nixos 26.05, nixpkgs unstable, opensuse-leap 16.0, ubuntu stonking

πŸ’– ARES_SEND(3) πŸ’–

okay bestie, welcome to the Library Functions Manual corner of the internet, we're talking about ares_send and honestly? it's giving "start a DNS query, immediately". let's get into it 🌸


✨ NAME ✨

ares_send β€” Initiate a DNS query πŸ’«


πŸŽ€ SYNOPSIS πŸŽ€

#include <ares.h>

typedef void (*ares_callback_dnsrec)(void *arg, ares_status_t status,
                                     size_t timeouts,
                                     const ares_dns_record_t *dnsrec);

ares_status_t ares_send_dnsrec(ares_channel_t *channel,
                               const ares_dns_record_t *dnsrec,
                               ares_callback_dnsrec callback,
                               void *arg, unsigned short *qid);

typedef void (*ares_callback)(void *arg, int status,
                              int timeouts, unsigned char *abuf,
                              int alen);

void ares_send(ares_channel_t *channel, const unsigned char *qbuf,
               int qlen, ares_callback callback, void *arg);

like… look at those signatures. no notes. 🫢


πŸ¦‹ DESCRIPTION πŸ¦‹

okay so. ares_send_dnsrec(3) kicks off a DNS query that's been formatted using the ares_dns_record_t * data structure β€” the one you built earlier with ares_dns_record_create(3) β€” and you hand that over in the dnsrec parameter. the callback you supply also gives you the response back as an ares_dns_record_t * data structure. structured in, structured out. iconic ✨

then there's ares_send(3), which is basically the same energy but old-school: it uses raw binary buffers with fully formatted DNS messages, passed in through the qbuf and qlen parameters. your callback then hands you back the raw binary DNS response in the abuf and alen parameters. and bestie, lowkey important: this method should be considered deprecated in favor of ares_send_dnsrec(3). πŸ’€ so like, use the new one if you can.

both functions take an initialized ares channel, identified by channel. no channel, no query, that's the vibe check.

ares_send_dnsrec(3) can also be given an optional output parameter, qid, which gets populated with the query id exactly as it was placed on the wire. cute little receipt 🧾

ares_send_dnsrec(3) returns an ares_status_t response code. this is useful for knowing that the query was enqueued properly β€” but heads up, the response code does not reflect the result of the query itself, just the result of the enqueuing of the query. so don't read into it, it's not that deep πŸ“

the query completing or failing might happen immediately (like, even before the function returns, wild) or it might happen later as network events get processed. main character energy: unpredictable timing.

⚠️ when the associated callback gets called, it's called with a channel lock held. so be careful, keep any processing minimal or you'll stall the DNS channel. no long gossip sessions in the callback, okay? πŸ’…

also the callback may be triggered from a different thread than the one that called ares_send_dnsrec(3) or ares_send(3). so if you're out here running your own event loops and not using ARES_OPT_EVENT_THREAD, take care to ensure any file descriptor lists are updated immediately within the eventloop when notified. yes this is a real requirement, no you cannot skip it πŸ™ˆ

the callback argument arg is copied straight from the arg parameter you passed to ares_send_dnsrec(3) or ares_send(3). copy-paste behavior, slay.

the callback argument status tells you whether the query succeeded and, if it didn't, how it failed. it can be any of these:

  • ARES_SUCCESS β€” The query completed. πŸŽ‰ we love to see it
  • ARES_EBADQUERY β€” The query buffer was poorly formed (was not long enough for a DNS header or was too long for TCP transmission).
  • ARES_ETIMEOUT β€” No name servers responded within the timeout period.
  • ARES_ECONNREFUSED β€” No name servers could be contacted.
  • ARES_ENOMEM β€” Memory was exhausted.
  • ARES_ECANCELLED β€” The query was cancelled.
  • ARES_EDESTRUCTION β€” The name service channel channel is being destroyed; the query will not be completed.
  • ARES_ENOSERVER β€” The query will not be completed because no DNS servers were configured on the channel.
  • ARES_EBADQUERY β€” Misformatted DNS query.

(yes, ARES_EBADQUERY shows up twice in the list. that's not a typo on my end, that's just what the page says. we keep the facts fr fr πŸ”₯)

the callback argument timeouts reports how many times a query timed out during the execution of the given request. count 'em.

if the query completed, then the callback argument dnsrec for ares_send_dnsrec(3), or abuf and alen for ares_send(3), will be non-NULL. so if you see NULL, it did not go well bestie 😭

πŸ”₯ important buffer lore: the abuf buffer is owned by the c-ares library and is only valid for the duration of the callback. the callback must not modify or free it, and must not retain a reference to it after returning; treat it as read-only. the parameter is intentionally not declared const solely to preserve API/ABI compatibility with existing applications. so like… do not touch, do not keep, do not take it home with you πŸ’…

unless the flag ARES_FLAG_NOCHECKRESP was set at channel initialization time, ares_send_dnsrec(3) and ares_send(3) will normally ignore responses whose questions do not match the supplied questions, as well as responses with reply codes of SERVFAIL, NOTIMP, and REFUSED. ✨

but β€” and this is the plot twist β€” unlike other query functions in the ares library, ares_send_dnsrec(3) and ares_send(3) do not inspect the header of the reply packet to determine the error status. so a callback status of ARES_SUCCESS does not reflect as much about the response as it does for other query functions. read that twice. it matters 🫢


🌈 AVAILABILITY 🌈

ares_send_dnsrec(3) was introduced in c-ares 1.28.0. newer than you thought, right? ⭐


πŸ‘‘ SEE ALSO πŸ‘‘

go read those too, they're all part of the lore πŸ’œ


okay that's the whole page, you ate it, periodt πŸŽ€ this little slice of the Library Functions Manual is dated 25 July 1998 and lives under the name ARES_SEND(3) β€” yes, 1998, it's an elder but it's still serving πŸ’– bye bestie! πŸ¦‹