c-ares documentation
c-ares provides a set of library functions, datatypes, and enumerations which integrators will use for their implementations. When you install c-ares, you get man pages which describe their use and meanings.
Manpages
- ares_cancel
- ares_create_query
- ares_destroy
- ares_destroy_options
- ares_dns_class_fromstr
- ares_dns_class_t
- ares_dns_class_tostr
- ares_dns_datatype_t
- ares_dns_flags_t
- ares_dns_mapping
- ares_dns_opcode_t
- ares_dns_opcode_tostr
- ares_dns_opt_datatype_t
- ares_dns_opt_get_datatype
- ares_dns_opt_get_name
- ares_dns_parse
- ares_dns_rcode_t
- ares_dns_rcode_tostr
- ares_dns_rec_type_fromstr
- ares_dns_rec_type_t
- ares_dns_rec_type_tostr
- ares_dns_record
- ares_dns_record_create
- ares_dns_record_destroy
- ares_dns_record_duplicate
- ares_dns_record_get_flags
- ares_dns_record_get_id
- ares_dns_record_get_opcode
- ares_dns_record_get_rcode
- ares_dns_record_query_add
- ares_dns_record_query_cnt
- ares_dns_record_query_get
- ares_dns_record_query_set_name
- ares_dns_record_query_set_type
- ares_dns_record_rr_add
- ares_dns_record_rr_cnt
- ares_dns_record_rr_del
- ares_dns_record_rr_get
- ares_dns_record_rr_get_const
- ares_dns_record_set_id
- ares_dns_rr
- ares_dns_rr_add_abin
- ares_dns_rr_del_abin
- ares_dns_rr_del_opt_byid
- ares_dns_rr_get_abin
- ares_dns_rr_get_abin_cnt
- ares_dns_rr_get_addr
- ares_dns_rr_get_addr6
- ares_dns_rr_get_bin
- ares_dns_rr_get_class
- ares_dns_rr_get_keys
- ares_dns_rr_get_name
- ares_dns_rr_get_opt
- ares_dns_rr_get_opt_byid
- ares_dns_rr_get_opt_cnt
- ares_dns_rr_get_str
- ares_dns_rr_get_ttl
- ares_dns_rr_get_type
- ares_dns_rr_get_u16
- ares_dns_rr_get_u32
- ares_dns_rr_get_u8
- ares_dns_rr_key_datatype
- ares_dns_rr_key_t
- ares_dns_rr_key_to_rec_type
- ares_dns_rr_key_tostr
- ares_dns_rr_set_addr
- ares_dns_rr_set_addr6
- ares_dns_rr_set_bin
- ares_dns_rr_set_opt
- ares_dns_rr_set_str
- ares_dns_rr_set_u16
- ares_dns_rr_set_u32
- ares_dns_rr_set_u8
- ares_dns_section_t
- ares_dns_section_tostr
- ares_dns_write
- ares_dup
- ares_expand_name
- ares_expand_string
- ares_fds
- ares_free_data
- ares_free_hostent
- ares_free_string
- ares_freeaddrinfo
- ares_get_servers
- ares_get_servers_csv
- ares_get_servers_ports
- ares_getaddrinfo
- ares_gethostbyaddr
- ares_gethostbyname
- ares_gethostbyname_file
- ares_getnameinfo
- ares_getsock
- ares_inet_ntop
- ares_inet_pton
- ares_init
- ares_init_options
- ares_library_cleanup
- ares_library_init
- ares_library_init_android
- ares_library_initialized
- ares_mkquery
- ares_opt_param_t
- ares_parse_a_reply
- ares_parse_aaaa_reply
- ares_parse_caa_reply
- ares_parse_mx_reply
- ares_parse_naptr_reply
- ares_parse_ns_reply
- ares_parse_ptr_reply
- ares_parse_soa_reply
- ares_parse_srv_reply
- ares_parse_txt_reply
- ares_parse_uri_reply
- ares_process
- ares_process_fd
- ares_process_fds
- ares_process_pending_write
- ares_query
- ares_query_dnsrec
- ares_queue
- ares_queue_active_queries
- ares_queue_wait_empty
- ares_reinit
- ares_save_options
- ares_search
- ares_search_dnsrec
- ares_send
- ares_send_dnsrec
- ares_set_local_dev
- ares_set_local_ip4
- ares_set_local_ip6
- ares_set_pending_write_cb
- ares_set_server_state_callback
- ares_set_servers
- ares_set_servers_csv
- ares_set_servers_ports
- ares_set_servers_ports_csv
- ares_set_socket_callback
- ares_set_socket_configure_callback
- ares_set_socket_functions
- ares_set_socket_functions_ex
- ares_set_sortlist
- ares_strerror
- ares_svcb_param_t
- ares_threadsafety
- ares_timeout
- ares_tlsa_match_t
- ares_tlsa_selector_t
- ares_tlsa_usage_t
- ares_version
Examples
Event Thread example (recommended)
example_ev.c
:
#include <stdio.h>
#include <string.h>
#include <ares.h>
/* Callback that is called when DNS query is finished */
static void addrinfo_cb(void *arg, int status, int timeouts,
struct ares_addrinfo *result)
{
(void)arg; /* Example does not use user context */
printf("Result: %s, timeouts: %d\n", ares_strerror(status), timeouts);
if (result) {
struct ares_addrinfo_node *node;
for (node = result->nodes; node != NULL; node = node->ai_next) {
char addr_buf[64] = "";
const void *ptr = NULL;
if (node->ai_family == AF_INET) {
const struct sockaddr_in *in_addr =
(const struct sockaddr_in *)((void *)node->ai_addr);
ptr = &in_addr->sin_addr;
} else if (node->ai_family == AF_INET6) {
const struct sockaddr_in6 *in_addr =
(const struct sockaddr_in6 *)((void *)node->ai_addr);
ptr = &in_addr->sin6_addr;
} else {
continue;
}
ares_inet_ntop(node->ai_family, ptr, addr_buf, sizeof(addr_buf));
printf("Addr: %s\n", addr_buf);
}
}
ares_freeaddrinfo(result);
}
int main(int argc, char **argv)
{
ares_channel_t *channel = NULL;
struct ares_options options;
int optmask = 0;
struct ares_addrinfo_hints hints;
if (argc != 2) {
printf("Usage: %s domain\n", argv[0]);
return 1;
}
/* Initialize library */
ares_library_init(ARES_LIB_INIT_ALL);
if (!ares_threadsafety()) {
printf("c-ares not compiled with thread support\n");
return 1;
}
/* Enable event thread so we don't have to monitor file descriptors */
memset(&options, 0, sizeof(options));
optmask |= ARES_OPT_EVENT_THREAD;
options.evsys = ARES_EVSYS_DEFAULT;
/* Initialize channel to run queries, a single channel can accept unlimited
* queries */
if (ares_init_options(&channel, &options, optmask) != ARES_SUCCESS) {
printf("c-ares initialization issue\n");
return 1;
}
/* Perform an IPv4 and IPv6 request for the provided domain name */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_flags = ARES_AI_CANONNAME;
ares_getaddrinfo(channel, argv[1], NULL, &hints, addrinfo_cb,
NULL /* user context not specified */);
/* Wait until no more requests are left to be processed */
ares_queue_wait_empty(channel, -1);
/* Cleanup */
ares_destroy(channel);
ares_library_cleanup();
return 0;
}
Compilation:
cc -I/usr/local/include -o example_ev example_ev.c -Wl,-rpath /usr/local/lib -lcares
Sock State Callback example
example_ss.c
:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <poll.h>
#include <ares.h>
typedef struct {
ares_channel_t *channel;
struct pollfd *poll_fds;
size_t poll_nfds;
size_t poll_fds_alloc;
ares_fd_events_t *ares_fds;
size_t ares_nfds;
} dnsstate_t;
void sock_state_cb(void *data, ares_socket_t socket_fd, int readable, int writable)
{
dnsstate_t *state = data;
size_t idx;
/* Find match */
for (idx=0; idx<state->poll_nfds; idx++) {
if (state->poll_fds[idx].fd == socket_fd) {
break;
}
}
/* Not found */
if (idx >= state->poll_nfds) {
/* Do nothing */
if (!readable && !writable) {
return;
}
/* Add */
state->poll_nfds++;
if (state->poll_nfds > state->poll_fds_alloc) {
state->poll_fds_alloc = state->poll_nfds;
state->poll_fds = realloc(state->poll_fds,
sizeof(*state->poll_fds) * state->poll_nfds);
/* Make the ares_fds the same size */
state->ares_fds = realloc(state->ares_fds,
sizeof(*state->ares_fds) * state->poll_nfds);
}
} else {
/* Remove */
if (!readable && !writable) {
memmove(&state->poll_fds[idx], &state->poll_fds[idx+1],
sizeof(*state->poll_fds) * (state->poll_nfds - idx - 1));
state->poll_nfds--;
return;
}
}
/* Update Poll Events (including on Add) */
state->poll_fds[idx].fd = socket_fd;
state->poll_fds[idx].events = 0;
if (readable) {
state->poll_fds[idx].events |= POLLIN;
}
if (writable) {
state->poll_fds[idx].events |= POLLOUT;
}
}
void process(dnsstate_t *state)
{
struct timeval tv;
while (1) {
int rv;
int timeout;
size_t i;
/* Since we don't have any other program state to wait on, we'll just
* stop looping when we know there are no remaining queries, which is
* easily indicated by ares_timeout() returning NULL when maxtv is NULL */
if (ares_timeout(state->channel, NULL, &tv) == NULL) {
break;
}
timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
rv = poll(state->poll_fds, state->poll_nfds, timeout);
if (rv < 0) {
continue;
} else if (rv == 0) {
/* Process timeouts */
ares_process_fd(state->channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
continue;
}
/* Form our notification array */
state->ares_nfds = 0;
for (i=0; i<state->poll_nfds; i++) {
size_t idx;
if (state->poll_fds[i].revents == 0) {
continue;
}
idx = state->ares_nfds++;
state->ares_fds[idx].fd = state->poll_fds[i].fd;
state->ares_fds[idx].events = 0;
if (state->poll_fds[i].revents & (POLLERR|POLLHUP|POLLIN)) {
state->ares_fds[idx].events |= ARES_FD_EVENT_READ;
}
if (state->poll_fds[i].revents & POLLOUT) {
state->ares_fds[idx].events |= ARES_FD_EVENT_WRITE;
}
}
/* Notify about read/write events per FD */
ares_process_fds(state->channel, state->ares_fds, state->ares_nfds,
ARES_PROCESS_FLAG_NONE);
}
}
/* Callback that is called when DNS query is finished */
static void addrinfo_cb(void *arg, int status, int timeouts,
struct ares_addrinfo *result)
{
(void)arg; /* Example does not use user context */
printf("Result: %s, timeouts: %d\n", ares_strerror(status), timeouts);
if (result) {
struct ares_addrinfo_node *node;
for (node = result->nodes; node != NULL; node = node->ai_next) {
char addr_buf[64] = "";
const void *ptr = NULL;
if (node->ai_family == AF_INET) {
const struct sockaddr_in *in_addr =
(const struct sockaddr_in *)((void *)node->ai_addr);
ptr = &in_addr->sin_addr;
} else if (node->ai_family == AF_INET6) {
const struct sockaddr_in6 *in_addr =
(const struct sockaddr_in6 *)((void *)node->ai_addr);
ptr = &in_addr->sin6_addr;
} else {
continue;
}
ares_inet_ntop(node->ai_family, ptr, addr_buf, sizeof(addr_buf));
printf("Addr: %s\n", addr_buf);
}
}
ares_freeaddrinfo(result);
}
int main(int argc, char **argv)
{
dnsstate_t state;
struct ares_options options;
int optmask = 0;
struct ares_addrinfo_hints hints;
memset(&state, 0, sizeof(state));
if (argc != 2) {
printf("Usage: %s domain\n", argv[0]);
return 1;
}
/* Initialize library */
ares_library_init(ARES_LIB_INIT_ALL);
/* Enable sock state callbacks, we should not use ares_fds() or ares_getsock()
* in modern implementations. */
memset(&options, 0, sizeof(options));
optmask |= ARES_OPT_SOCK_STATE_CB;
options.sock_state_cb = sock_state_cb;
options.sock_state_cb_data = &state;
/* Initialize channel to run queries, a single channel can accept unlimited
* queries */
if (ares_init_options(&state.channel, &options, optmask) != ARES_SUCCESS) {
printf("c-ares initialization issue\n");
return 1;
}
/* Perform an IPv4 and IPv6 request for the provided domain name */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_flags = ARES_AI_CANONNAME;
ares_getaddrinfo(state.channel, argv[1], NULL, &hints, addrinfo_cb,
NULL /* user context not specified */);
/* Wait until no more requests are left to be processed */
process(&state);
/* Cleanup */
ares_destroy(state.channel);
free(state.poll_fds);
free(state.ares_fds);
ares_library_cleanup();
return 0;
}
Compilation:
cc -I/usr/local/include -o example_ss example_ss.c -Wl,-rpath /usr/local/lib -lcares