2 This file is part of libasyncns.
4 Copyright 2005-2008 Lennart Poettering
6 libasyncns is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation, either version 2.1 of the
9 License, or (at your option) any later version.
11 libasyncns is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with libasyncns. If not, see
18 <http://www.gnu.org/licenses/>.
29 #include <sys/select.h>
35 #include <sys/types.h>
37 #include <netinet/in.h>
38 #include <arpa/nameser.h>
42 #include <sys/resource.h>
46 #ifdef HAVE_SYS_PRCTL_H
47 #include <sys/prctl.h>
53 #define MAX_WORKERS 16
54 #define MAX_QUERIES 256
55 #define BUFSIZE (10240)
78 int fds[MESSAGE_FD_MAX];
80 pthread_t workers[MAX_WORKERS];
81 unsigned valid_workers;
83 unsigned current_id, current_index;
84 asyncns_query_t* queries[MAX_QUERIES];
86 asyncns_query_t *done_head, *done_tail;
92 struct asyncns_query {
97 asyncns_query_t *done_next, *done_prev;
101 struct addrinfo *addrinfo;
106 typedef struct rheader {
112 typedef struct addrinfo_request {
113 struct rheader header;
119 size_t node_len, service_len;
120 } addrinfo_request_t;
122 typedef struct addrinfo_response {
123 struct rheader header;
127 /* followed by addrinfo_serialization[] */
128 } addrinfo_response_t;
130 typedef struct addrinfo_serialization {
136 size_t canonname_len;
137 /* Followed by ai_addr amd ai_canonname with variable lengths */
138 } addrinfo_serialization_t;
140 typedef struct nameinfo_request {
141 struct rheader header;
143 socklen_t sockaddr_len;
144 int gethost, getserv;
145 } nameinfo_request_t;
147 typedef struct nameinfo_response {
148 struct rheader header;
149 size_t hostlen, servlen;
153 } nameinfo_response_t;
155 typedef struct res_request {
156 struct rheader header;
162 typedef struct res_response {
163 struct rheader header;
169 typedef union packet {
171 addrinfo_request_t addrinfo_request;
172 addrinfo_response_t addrinfo_response;
173 nameinfo_request_t nameinfo_request;
174 nameinfo_response_t nameinfo_response;
175 res_request_t res_request;
176 res_response_t res_response;
179 static int send_died(int out_fd) {
183 rh.type = RESPONSE_DIED;
185 rh.length = sizeof(rh);
187 return send(out_fd, &rh, rh.length, MSG_NOSIGNAL);
190 static void *serialize_addrinfo(void *p, const struct addrinfo *ai, size_t *length, size_t maxlength) {
191 addrinfo_serialization_t s;
196 assert(*length <= maxlength);
198 cnl = (ai->ai_canonname ? strlen(ai->ai_canonname)+1 : 0);
199 l = sizeof(addrinfo_serialization_t) + ai->ai_addrlen + cnl;
201 if (*length + l > maxlength)
204 s.ai_flags = ai->ai_flags;
205 s.ai_family = ai->ai_family;
206 s.ai_socktype = ai->ai_socktype;
207 s.ai_protocol = ai->ai_protocol;
208 s.ai_addrlen = ai->ai_addrlen;
209 s.canonname_len = cnl;
211 memcpy((uint8_t*) p, &s, sizeof(addrinfo_serialization_t));
212 memcpy((uint8_t*) p + sizeof(addrinfo_serialization_t), ai->ai_addr, ai->ai_addrlen);
214 if (ai->ai_canonname)
215 strcpy((char*) p + sizeof(addrinfo_serialization_t) + ai->ai_addrlen, ai->ai_canonname);
218 return (uint8_t*) p + l;
221 static int send_addrinfo_reply(int out_fd, unsigned id, int ret, struct addrinfo *ai, int _errno, int _h_errno) {
222 addrinfo_response_t data[BUFSIZE/sizeof(addrinfo_response_t) + 1] = {};
223 addrinfo_response_t *resp = data;
226 resp->header.type = RESPONSE_ADDRINFO;
227 resp->header.id = id;
228 resp->header.length = sizeof(addrinfo_response_t);
230 resp->_errno = _errno;
231 resp->_h_errno = _h_errno;
233 if (ret == 0 && ai) {
237 for (k = ai; k; k = k->ai_next) {
238 if (!(p = serialize_addrinfo(p, k, &resp->header.length, (char*) data + BUFSIZE - (char*) p))) {
239 resp->ret = EAI_MEMORY;
248 return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL);
251 static int send_nameinfo_reply(int out_fd, unsigned id, int ret, const char *host, const char *serv, int _errno, int _h_errno) {
252 nameinfo_response_t data[BUFSIZE/sizeof(nameinfo_response_t) + 1] = {};
254 nameinfo_response_t *resp = data;
258 sl = serv ? strlen(serv)+1 : 0;
259 hl = host ? strlen(host)+1 : 0;
261 resp->header.type = RESPONSE_NAMEINFO;
262 resp->header.id = id;
263 resp->header.length = sizeof(nameinfo_response_t) + hl + sl;
265 resp->_errno = _errno;
266 resp->_h_errno = _h_errno;
270 assert(sizeof(data) >= resp->header.length);
273 memcpy((uint8_t *)data + sizeof(nameinfo_response_t), host, hl);
276 memcpy((uint8_t *)data + sizeof(nameinfo_response_t) + hl, serv, sl);
278 return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL);
281 static int send_res_reply(int out_fd, unsigned id, const unsigned char *answer, int ret, int _errno, int _h_errno) {
282 res_response_t data[BUFSIZE/sizeof(res_response_t) + 1] = {};
283 res_response_t *resp = data;
287 resp->header.type = RESPONSE_RES;
288 resp->header.id = id;
289 resp->header.length = sizeof(res_response_t) + (ret < 0 ? 0 : ret);
291 resp->_errno = _errno;
292 resp->_h_errno = _h_errno;
294 assert(sizeof(data) >= resp->header.length);
297 memcpy((uint8_t *)data + sizeof(res_response_t), answer, ret);
299 return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL);
302 static int handle_request(int out_fd, const packet_t *packet, size_t length) {
303 const rheader_t *req;
306 req = &packet->rheader;
308 assert(length >= sizeof(rheader_t));
309 assert(length == req->length);
312 case REQUEST_ADDRINFO: {
313 struct addrinfo ai = {}, *result = NULL;
314 const addrinfo_request_t *ai_req = &packet->addrinfo_request;
315 const char *node, *service;
318 assert(length >= sizeof(addrinfo_request_t));
319 assert(length == sizeof(addrinfo_request_t) + ai_req->node_len + ai_req->service_len);
321 ai.ai_flags = ai_req->ai_flags;
322 ai.ai_family = ai_req->ai_family;
323 ai.ai_socktype = ai_req->ai_socktype;
324 ai.ai_protocol = ai_req->ai_protocol;
326 node = ai_req->node_len ? (const char*) ai_req + sizeof(addrinfo_request_t) : NULL;
327 service = ai_req->service_len ? (const char*) ai_req + sizeof(addrinfo_request_t) + ai_req->node_len : NULL;
329 ret = getaddrinfo(node, service,
330 ai_req->hints_is_null ? NULL : &ai,
333 /* send_addrinfo_reply() frees result */
334 return send_addrinfo_reply(out_fd, req->id, ret, result, errno, h_errno);
337 case REQUEST_NAMEINFO: {
339 const nameinfo_request_t *ni_req = &packet->nameinfo_request;
340 char hostbuf[NI_MAXHOST], servbuf[NI_MAXSERV];
341 struct sockaddr_storage sa;
343 assert(length >= sizeof(nameinfo_request_t));
344 assert(length == sizeof(nameinfo_request_t) + ni_req->sockaddr_len);
346 memcpy(&sa, (const uint8_t *) ni_req + sizeof(nameinfo_request_t), ni_req->sockaddr_len);
348 ret = getnameinfo((struct sockaddr *)&sa, ni_req->sockaddr_len,
349 ni_req->gethost ? hostbuf : NULL, ni_req->gethost ? sizeof(hostbuf) : 0,
350 ni_req->getserv ? servbuf : NULL, ni_req->getserv ? sizeof(servbuf) : 0,
353 return send_nameinfo_reply(out_fd, req->id, ret,
354 ret == 0 && ni_req->gethost ? hostbuf : NULL,
355 ret == 0 && ni_req->getserv ? servbuf : NULL,
359 case REQUEST_RES_QUERY:
360 case REQUEST_RES_SEARCH: {
362 HEADER answer[BUFSIZE/sizeof(HEADER) + 1];
363 const res_request_t *res_req = &packet->res_request;
366 assert(length >= sizeof(res_request_t));
367 assert(length == sizeof(res_request_t) + res_req->dname_len);
369 dname = (const char *) req + sizeof(res_request_t);
371 if (req->type == REQUEST_RES_QUERY)
372 ret = res_query(dname, res_req->class, res_req->type, (unsigned char *) answer, BUFSIZE);
374 ret = res_search(dname, res_req->class, res_req->type, (unsigned char *) answer, BUFSIZE);
376 return send_res_reply(out_fd, req->id, (unsigned char *) answer, ret, errno, h_errno);
379 case REQUEST_TERMINATE:
390 static void* thread_worker(void *p) {
391 asyncns_t *asyncns = p;
394 /* No signals in this thread please */
395 sigfillset(&fullset);
396 pthread_sigmask(SIG_BLOCK, &fullset, NULL);
398 while (!asyncns->dead) {
399 packet_t buf[BUFSIZE/sizeof(packet_t) + 1];
402 length = recv(asyncns->fds[REQUEST_RECV_FD], buf, sizeof(buf), 0);
405 if (length < 0 && (errno == EAGAIN || errno == EINTR))
413 if (handle_request(asyncns->fds[RESPONSE_SEND_FD], buf, (size_t) length) < 0)
417 send_died(asyncns->fds[RESPONSE_SEND_FD]);
422 asyncns_t* asyncns_new(unsigned n_proc) {
424 asyncns_t *asyncns = NULL;
428 if (n_proc > MAX_WORKERS)
429 n_proc = MAX_WORKERS;
431 asyncns = malloc(sizeof(asyncns_t));
438 asyncns->valid_workers = 0;
440 for (i = 0; i < MESSAGE_FD_MAX; i++)
441 asyncns->fds[i] = -1;
443 memset(asyncns->queries, 0, sizeof(asyncns->queries));
446 if (socketpair(PF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, asyncns->fds) < 0 ||
447 socketpair(PF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, asyncns->fds+2) < 0) {
449 /* Try again, without SOCK_CLOEXEC */
450 if (errno == EINVAL) {
452 if (socketpair(PF_UNIX, SOCK_DGRAM, 0, asyncns->fds) < 0 ||
453 socketpair(PF_UNIX, SOCK_DGRAM, 0, asyncns->fds+2) < 0)
461 for (i = 0; i < MESSAGE_FD_MAX; i++)
462 fd_cloexec(asyncns->fds[i], true);
464 for (asyncns->valid_workers = 0; asyncns->valid_workers < n_proc; asyncns->valid_workers++) {
467 if ((r = pthread_create(&asyncns->workers[asyncns->valid_workers], NULL, thread_worker, asyncns)) != 0) {
473 asyncns->current_index = asyncns->current_id = 0;
474 asyncns->done_head = asyncns->done_tail = NULL;
475 asyncns->n_queries = 0;
477 fd_nonblock(asyncns->fds[RESPONSE_RECV_FD], true);
483 asyncns_free(asyncns);
488 void asyncns_free(asyncns_t *asyncns) {
490 int saved_errno = errno;
497 if (asyncns->fds[REQUEST_SEND_FD] >= 0) {
500 req.type = REQUEST_TERMINATE;
501 req.length = sizeof(req);
504 /* Send one termination packet for each worker */
505 for (p = 0; p < asyncns->valid_workers; p++)
506 send(asyncns->fds[REQUEST_SEND_FD], &req, req.length, MSG_NOSIGNAL);
509 /* Now terminate them and wait until they are gone. */
510 for (p = 0; p < asyncns->valid_workers; p++) {
512 if (pthread_join(asyncns->workers[p], NULL) != EINTR)
517 /* Close all communication channels */
518 for (i = 0; i < MESSAGE_FD_MAX; i++)
519 if (asyncns->fds[i] >= 0)
520 close(asyncns->fds[i]);
522 for (p = 0; p < MAX_QUERIES; p++)
523 if (asyncns->queries[p])
524 asyncns_cancel(asyncns, asyncns->queries[p]);
531 int asyncns_fd(asyncns_t *asyncns) {
534 return asyncns->fds[RESPONSE_RECV_FD];
537 static asyncns_query_t *lookup_query(asyncns_t *asyncns, unsigned id) {
541 if ((q = asyncns->queries[id % MAX_QUERIES]))
548 static void complete_query(asyncns_t *asyncns, asyncns_query_t *q) {
555 if ((q->done_prev = asyncns->done_tail))
556 asyncns->done_tail->done_next = q;
558 asyncns->done_head = q;
560 asyncns->done_tail = q;
564 static const void *unserialize_addrinfo(const void *p, struct addrinfo **ret_ai, size_t *length) {
565 addrinfo_serialization_t s;
572 if (*length < sizeof(addrinfo_serialization_t))
575 memcpy(&s, p, sizeof(s));
577 l = sizeof(addrinfo_serialization_t) + s.ai_addrlen + s.canonname_len;
581 if (!(ai = malloc(sizeof(struct addrinfo))))
585 ai->ai_canonname = NULL;
588 if (s.ai_addrlen && !(ai->ai_addr = malloc(s.ai_addrlen)))
591 if (s.canonname_len && !(ai->ai_canonname = malloc(s.canonname_len)))
594 ai->ai_flags = s.ai_flags;
595 ai->ai_family = s.ai_family;
596 ai->ai_socktype = s.ai_socktype;
597 ai->ai_protocol = s.ai_protocol;
598 ai->ai_addrlen = s.ai_addrlen;
601 memcpy(ai->ai_addr, (const uint8_t*) p + sizeof(addrinfo_serialization_t), s.ai_addrlen);
603 if (ai->ai_canonname)
604 memcpy(ai->ai_canonname, (const uint8_t*) p + sizeof(addrinfo_serialization_t) + s.ai_addrlen, s.canonname_len);
609 return (const uint8_t*) p + l;
614 asyncns_freeaddrinfo(ai);
619 static int handle_response(asyncns_t *asyncns, const packet_t *packet, size_t length) {
620 const rheader_t *resp;
625 resp = &packet->rheader;
627 assert(length >= sizeof(rheader_t));
628 assert(length == resp->length);
630 if (resp->type == RESPONSE_DIED) {
635 if (!(q = lookup_query(asyncns, resp->id)))
638 switch (resp->type) {
639 case RESPONSE_ADDRINFO: {
640 const addrinfo_response_t *ai_resp = &packet->addrinfo_response;
643 struct addrinfo *prev = NULL;
645 assert(length >= sizeof(addrinfo_response_t));
646 assert(q->type == REQUEST_ADDRINFO);
648 q->ret = ai_resp->ret;
649 q->_errno = ai_resp->_errno;
650 q->_h_errno = ai_resp->_h_errno;
651 l = length - sizeof(addrinfo_response_t);
652 p = (const uint8_t*) resp + sizeof(addrinfo_response_t);
655 struct addrinfo *ai = NULL;
656 p = unserialize_addrinfo(p, &ai, &l);
671 complete_query(asyncns, q);
675 case RESPONSE_NAMEINFO: {
676 const nameinfo_response_t *ni_resp = &packet->nameinfo_response;
678 assert(length >= sizeof(nameinfo_response_t));
679 assert(q->type == REQUEST_NAMEINFO);
681 q->ret = ni_resp->ret;
682 q->_errno = ni_resp->_errno;
683 q->_h_errno = ni_resp->_h_errno;
685 if (ni_resp->hostlen)
686 if (!(q->host = strndup((const char*) ni_resp + sizeof(nameinfo_response_t), ni_resp->hostlen-1)))
689 if (ni_resp->servlen)
690 if (!(q->serv = strndup((const char*) ni_resp + sizeof(nameinfo_response_t) + ni_resp->hostlen, ni_resp->servlen-1)))
693 complete_query(asyncns, q);
698 const res_response_t *res_resp = &packet->res_response;
700 assert(length >= sizeof(res_response_t));
701 assert(q->type == REQUEST_RES_QUERY || q->type == REQUEST_RES_SEARCH);
703 q->ret = res_resp->ret;
704 q->_errno = res_resp->_errno;
705 q->_h_errno = res_resp->_h_errno;
707 if (res_resp->ret >= 0) {
708 if (!(q->serv = malloc(res_resp->ret))) {
712 memcpy(q->serv, (const char *)resp + sizeof(res_response_t), res_resp->ret);
715 complete_query(asyncns, q);
726 int asyncns_wait(asyncns_t *asyncns, int block) {
731 packet_t buf[BUFSIZE/sizeof(packet_t) + 1];
739 if (((l = recv(asyncns->fds[RESPONSE_RECV_FD], buf, sizeof(buf), 0)) < 0)) {
745 if (!block || handled)
749 FD_SET(asyncns->fds[RESPONSE_RECV_FD], &fds);
751 if (select(asyncns->fds[RESPONSE_RECV_FD]+1, &fds, NULL, NULL, NULL) < 0)
757 if (handle_response(asyncns, buf, (size_t) l) < 0)
764 static asyncns_query_t *alloc_query(asyncns_t *asyncns) {
768 if (asyncns->n_queries >= MAX_QUERIES) {
773 while (asyncns->queries[asyncns->current_index]) {
775 asyncns->current_index++;
776 asyncns->current_id++;
778 while (asyncns->current_index >= MAX_QUERIES)
779 asyncns->current_index -= MAX_QUERIES;
782 if (!(q = asyncns->queries[asyncns->current_index] = malloc(sizeof(asyncns_query_t)))) {
787 asyncns->n_queries++;
789 q->asyncns = asyncns;
791 q->id = asyncns->current_id;
792 q->done_next = q->done_prev = NULL;
798 q->host = q->serv = NULL;
803 asyncns_query_t* asyncns_getaddrinfo(asyncns_t *asyncns, const char *node, const char *service, const struct addrinfo *hints) {
804 addrinfo_request_t data[BUFSIZE/sizeof(addrinfo_request_t) + 1] = {};
805 addrinfo_request_t *req = data;
808 assert(node || service);
815 if (!(q = alloc_query(asyncns)))
819 req->node_len = node ? strlen(node)+1 : 0;
820 req->service_len = service ? strlen(service)+1 : 0;
822 req->header.id = q->id;
823 req->header.type = q->type = REQUEST_ADDRINFO;
824 req->header.length = sizeof(addrinfo_request_t) + req->node_len + req->service_len;
826 if (req->header.length > BUFSIZE) {
831 if (!(req->hints_is_null = !hints)) {
832 req->ai_flags = hints->ai_flags;
833 req->ai_family = hints->ai_family;
834 req->ai_socktype = hints->ai_socktype;
835 req->ai_protocol = hints->ai_protocol;
839 strcpy((char*) req + sizeof(addrinfo_request_t), node);
842 strcpy((char*) req + sizeof(addrinfo_request_t) + req->node_len, service);
844 if (send(asyncns->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0)
851 asyncns_cancel(asyncns, q);
856 int asyncns_getaddrinfo_done(asyncns_t *asyncns, asyncns_query_t* q, struct addrinfo **ret_res) {
860 assert(q->asyncns == asyncns);
861 assert(q->type == REQUEST_ADDRINFO);
871 *ret_res = q->addrinfo;
876 if (ret == EAI_SYSTEM)
880 h_errno = q->_h_errno;
882 asyncns_cancel(asyncns, q);
887 asyncns_query_t* asyncns_getnameinfo(asyncns_t *asyncns, const struct sockaddr *sa, socklen_t salen, int flags, int gethost, int getserv) {
888 nameinfo_request_t data[BUFSIZE/sizeof(nameinfo_request_t) + 1] = {};
889 nameinfo_request_t *req = data;
901 if (!(q = alloc_query(asyncns)))
905 req->header.id = q->id;
906 req->header.type = q->type = REQUEST_NAMEINFO;
907 req->header.length = sizeof(nameinfo_request_t) + salen;
909 if (req->header.length > BUFSIZE) {
915 req->sockaddr_len = salen;
916 req->gethost = gethost;
917 req->getserv = getserv;
919 memcpy((uint8_t*) req + sizeof(nameinfo_request_t), sa, salen);
921 if (send(asyncns->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0)
928 asyncns_cancel(asyncns, q);
933 int asyncns_getnameinfo_done(asyncns_t *asyncns, asyncns_query_t* q, char *ret_host, size_t hostlen, char *ret_serv, size_t servlen) {
937 assert(q->asyncns == asyncns);
938 assert(q->type == REQUEST_NAMEINFO);
939 assert(!ret_host || hostlen);
940 assert(!ret_serv || servlen);
950 if (ret_host && q->host) {
951 strncpy(ret_host, q->host, hostlen);
952 ret_host[hostlen-1] = 0;
955 if (ret_serv && q->serv) {
956 strncpy(ret_serv, q->serv, servlen);
957 ret_serv[servlen-1] = 0;
962 if (ret == EAI_SYSTEM)
966 h_errno = q->_h_errno;
968 asyncns_cancel(asyncns, q);
973 static asyncns_query_t * asyncns_res(asyncns_t *asyncns, query_type_t qtype, const char *dname, int class, int type) {
974 res_request_t data[BUFSIZE/sizeof(res_request_t) + 1];
975 res_request_t *req = data;
986 if (!(q = alloc_query(asyncns)))
989 req->dname_len = strlen(dname) + 1;
991 req->header.id = q->id;
992 req->header.type = q->type = qtype;
993 req->header.length = sizeof(res_request_t) + req->dname_len;
995 if (req->header.length > BUFSIZE) {
1003 strcpy((char*) req + sizeof(res_request_t), dname);
1005 if (send(asyncns->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0)
1012 asyncns_cancel(asyncns, q);
1017 asyncns_query_t* asyncns_res_query(asyncns_t *asyncns, const char *dname, int class, int type) {
1018 return asyncns_res(asyncns, REQUEST_RES_QUERY, dname, class, type);
1021 asyncns_query_t* asyncns_res_search(asyncns_t *asyncns, const char *dname, int class, int type) {
1022 return asyncns_res(asyncns, REQUEST_RES_SEARCH, dname, class, type);
1025 int asyncns_res_done(asyncns_t *asyncns, asyncns_query_t* q, unsigned char **answer) {
1029 assert(q->asyncns == asyncns);
1030 assert(q->type == REQUEST_RES_QUERY || q->type == REQUEST_RES_SEARCH);
1033 if (asyncns->dead) {
1043 *answer = (unsigned char *)q->serv;
1050 h_errno = q->_h_errno;
1053 asyncns_cancel(asyncns, q);
1055 return ret < 0 ? -errno : ret;
1058 asyncns_query_t* asyncns_getnext(asyncns_t *asyncns) {
1060 return asyncns->done_head;
1063 int asyncns_getnqueries(asyncns_t *asyncns) {
1065 return asyncns->n_queries;
1068 void asyncns_cancel(asyncns_t *asyncns, asyncns_query_t* q) {
1070 int saved_errno = errno;
1074 assert(q->asyncns == asyncns);
1075 assert(asyncns->n_queries > 0);
1080 q->done_prev->done_next = q->done_next;
1082 asyncns->done_head = q->done_next;
1085 q->done_next->done_prev = q->done_prev;
1087 asyncns->done_tail = q->done_prev;
1090 i = q->id % MAX_QUERIES;
1091 assert(asyncns->queries[i] == q);
1092 asyncns->queries[i] = NULL;
1094 asyncns_freeaddrinfo(q->addrinfo);
1098 asyncns->n_queries--;
1101 errno = saved_errno;
1104 void asyncns_freeaddrinfo(struct addrinfo *ai) {
1105 int saved_errno = errno;
1108 struct addrinfo *next = ai->ai_next;
1111 free(ai->ai_canonname);
1117 errno = saved_errno;
1120 void asyncns_freeanswer(unsigned char *answer) {
1121 int saved_errno = errno;
1126 /* Please note that this function is new in libasyncns 0.4. In
1127 * older versions you were supposed to free the answer directly
1128 * with free(). Hence, if this function is changed to do more than
1129 * just a simple free() this must be considered ABI/API breakage! */
1133 errno = saved_errno;
1136 int asyncns_isdone(asyncns_t *asyncns, asyncns_query_t*q) {
1139 assert(q->asyncns == asyncns);
1144 void asyncns_setuserdata(asyncns_t *asyncns, asyncns_query_t *q, void *userdata) {
1147 assert(q->asyncns = asyncns);
1149 q->userdata = userdata;
1152 void* asyncns_getuserdata(asyncns_t *asyncns, asyncns_query_t *q) {
1155 assert(q->asyncns = asyncns);