menu | title | layout |
---|---|---|
Docs |
c-ares documentation |
page |
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.
{% assign docs_paths = site.pages | where_exp: "page", "page.path contains 'docs/'" | map: "path" | sort -%} {%- for path in docs_paths -%} {%- assign my_page = site.pages | where: "path", path | first -%}
- [{{ my_page.path | replace: "docs/", "" | replace: ".html", "" }}](/{{ my_page.path }}) {% endfor -%}
example_ev.c
:
{% highlight 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; } {% endhighlight %}
Compilation: {% highlight bash %} cc -I/usr/local/include -o example_ev example_ev.c -Wl,-rpath /usr/local/lib -lcares {% endhighlight %}
example_ss.c
:
{% highlight 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; idxpoll_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; } {% endhighlight %}
Compilation: {% highlight bash %} cc -I/usr/local/include -o example_ss example_ss.c -Wl,-rpath /usr/local/lib -lcares {% endhighlight %}