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/>.
22 #include "g-asyncns.h"
25 /* #undef HAVE_PTHREAD */
32 #ifdef HAVE_SYS_SELECT_H
33 #include <sys/select.h>
41 #include <sys/types.h>
43 #include <netinet/in.h>
44 #include <arpa/nameser.h>
48 #ifdef HAVE_SYS_TIME_H
52 #include <sys/resource.h>
56 #ifdef HAVE_INTTYPES_H
60 #ifdef HAVE_SYS_PRCTL_H
61 #include <sys/prctl.h>
71 #define MSG_NOSIGNAL 0
74 #define MAX_WORKERS 16
75 #define MAX_QUERIES 256
76 #define BUFSIZE (10240)
102 pid_t workers[MAX_WORKERS];
104 pthread_t workers[MAX_WORKERS];
106 unsigned valid_workers;
108 unsigned current_id, current_index;
109 _g_asyncns_query_t* queries[MAX_QUERIES];
111 _g_asyncns_query_t *done_head, *done_tail;
117 struct _g_asyncns_query {
118 _g_asyncns_t *asyncns;
122 _g_asyncns_query_t *done_next, *done_prev;
126 struct addrinfo *addrinfo;
131 typedef struct rheader {
137 typedef struct addrinfo_request {
138 struct rheader header;
144 size_t node_len, service_len;
145 } addrinfo_request_t;
147 typedef struct addrinfo_response {
148 struct rheader header;
152 /* followed by addrinfo_serialization[] */
153 } addrinfo_response_t;
155 typedef struct addrinfo_serialization {
161 size_t canonname_len;
162 /* Followed by ai_addr amd ai_canonname with variable lengths */
163 } addrinfo_serialization_t;
165 typedef struct nameinfo_request {
166 struct rheader header;
168 socklen_t sockaddr_len;
169 int gethost, getserv;
170 } nameinfo_request_t;
172 typedef struct nameinfo_response {
173 struct rheader header;
174 size_t hostlen, servlen;
178 } nameinfo_response_t;
180 typedef struct res_request {
181 struct rheader header;
187 typedef struct res_response {
188 struct rheader header;
194 typedef union packet {
196 addrinfo_request_t addrinfo_request;
197 addrinfo_response_t addrinfo_response;
198 nameinfo_request_t nameinfo_request;
199 nameinfo_response_t nameinfo_response;
200 res_request_t res_request;
201 res_response_t res_response;
206 static char *strndup(const char *s, size_t l) {
214 if (!(n = malloc(a+1)))
227 static int close_allv(const int except_fds[]) {
237 if ((d = opendir("/proc/self/fd"))) {
241 while ((de = readdir(d))) {
247 if (de->d_name[0] == '.')
251 l = strtol(de->d_name, &e, 10);
252 if (errno != 0 || !e || *e) {
260 if ((long) fd != l) {
273 for (i = 0; except_fds[i] >= 0; i++)
274 if (except_fds[i] == fd) {
299 if (getrlimit(RLIMIT_NOFILE, &rl) > 0)
300 maxfd = (int) rl.rlim_max;
302 maxfd = sysconf(_SC_OPEN_MAX);
304 for (fd = 3; fd < maxfd; fd++) {
308 for (i = 0; except_fds[i] >= 0; i++)
309 if (except_fds[i] == fd) {
317 if (close(fd) < 0 && errno != EBADF)
324 static int reset_sigsv(const int except[]) {
328 for (sig = 1; sig < NSIG; sig++) {
340 for (i = 0; except[i] > 0; i++) {
341 if (sig == except[i]) {
352 memset(&sa, 0, sizeof(sa));
353 sa.sa_handler = SIG_DFL;
355 /* On Linux the first two RT signals are reserved by
356 * glibc, and sigaction() will return EINVAL for them. */
357 if ((sigaction(sig, &sa, NULL) < 0))
366 static int ignore_sigsv(const int ignore[]) {
370 for (i = 0; ignore[i] > 0; i++) {
373 memset(&sa, 0, sizeof(sa));
374 sa.sa_handler = SIG_IGN;
376 if ((sigaction(ignore[i], &sa, NULL) < 0))
385 static int fd_nonblock(int fd) {
389 if ((i = fcntl(fd, F_GETFL, 0)) < 0)
395 return fcntl(fd, F_SETFL, i | O_NONBLOCK);
398 static int fd_cloexec(int fd) {
402 if ((v = fcntl(fd, F_GETFD, 0)) < 0)
408 return fcntl(fd, F_SETFD, v | FD_CLOEXEC);
411 static int send_died(int out_fd) {
415 memset(&rh, 0, sizeof(rh));
416 rh.type = RESPONSE_DIED;
418 rh.length = sizeof(rh);
420 return send(out_fd, &rh, rh.length, MSG_NOSIGNAL);
423 static void *serialize_addrinfo(void *p, const struct addrinfo *ai, size_t *length, size_t maxlength) {
424 addrinfo_serialization_t s;
429 assert(*length <= maxlength);
431 cnl = (ai->ai_canonname ? strlen(ai->ai_canonname)+1 : 0);
432 l = sizeof(addrinfo_serialization_t) + ai->ai_addrlen + cnl;
434 if (*length + l > maxlength)
437 s.ai_flags = ai->ai_flags;
438 s.ai_family = ai->ai_family;
439 s.ai_socktype = ai->ai_socktype;
440 s.ai_protocol = ai->ai_protocol;
441 s.ai_addrlen = ai->ai_addrlen;
442 s.canonname_len = cnl;
444 memcpy((uint8_t*) p, &s, sizeof(addrinfo_serialization_t));
445 memcpy((uint8_t*) p + sizeof(addrinfo_serialization_t), ai->ai_addr, ai->ai_addrlen);
447 if (ai->ai_canonname)
448 strcpy((char*) p + sizeof(addrinfo_serialization_t) + ai->ai_addrlen, ai->ai_canonname);
451 return (uint8_t*) p + l;
454 static int send_addrinfo_reply(int out_fd, unsigned id, int ret, struct addrinfo *ai, int _errno, int _h_errno) {
455 addrinfo_response_t data[BUFSIZE/sizeof(addrinfo_response_t) + 1];
456 addrinfo_response_t *resp = data;
459 memset(data, 0, sizeof(data));
460 resp->header.type = RESPONSE_ADDRINFO;
461 resp->header.id = id;
462 resp->header.length = sizeof(addrinfo_response_t);
464 resp->_errno = _errno;
465 resp->_h_errno = _h_errno;
467 if (ret == 0 && ai) {
471 for (k = ai; k; k = k->ai_next) {
473 if (!(p = serialize_addrinfo(p, k, &resp->header.length, (char*) data + BUFSIZE - (char*) p))) {
474 resp->ret = EAI_MEMORY;
483 return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL);
486 static int send_nameinfo_reply(int out_fd, unsigned id, int ret, const char *host, const char *serv, int _errno, int _h_errno) {
487 nameinfo_response_t data[BUFSIZE/sizeof(nameinfo_response_t) + 1];
489 nameinfo_response_t *resp = data;
493 sl = serv ? strlen(serv)+1 : 0;
494 hl = host ? strlen(host)+1 : 0;
496 memset(data, 0, sizeof(data));
497 resp->header.type = RESPONSE_NAMEINFO;
498 resp->header.id = id;
499 resp->header.length = sizeof(nameinfo_response_t) + hl + sl;
501 resp->_errno = _errno;
502 resp->_h_errno = _h_errno;
506 assert(sizeof(data) >= resp->header.length);
509 memcpy((uint8_t *)data + sizeof(nameinfo_response_t), host, hl);
512 memcpy((uint8_t *)data + sizeof(nameinfo_response_t) + hl, serv, sl);
514 return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL);
517 static int send_res_reply(int out_fd, unsigned id, const unsigned char *answer, int ret, int _errno, int _h_errno) {
518 res_response_t data[BUFSIZE/sizeof(res_response_t) + 1];
519 res_response_t *resp = data;
523 memset(data, 0, sizeof(data));
524 resp->header.type = RESPONSE_RES;
525 resp->header.id = id;
526 resp->header.length = sizeof(res_response_t) + (ret < 0 ? 0 : ret);
528 resp->_errno = _errno;
529 resp->_h_errno = _h_errno;
531 assert(sizeof(data) >= resp->header.length);
534 memcpy((uint8_t *)data + sizeof(res_response_t), answer, ret);
536 return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL);
539 static int handle_request(int out_fd, const packet_t *packet, size_t length) {
540 const rheader_t *req;
543 req = &packet->rheader;
545 assert(length >= sizeof(rheader_t));
546 assert(length == req->length);
550 case REQUEST_ADDRINFO: {
551 struct addrinfo ai, *result = NULL;
552 const addrinfo_request_t *ai_req = &packet->addrinfo_request;
553 const char *node, *service;
556 assert(length >= sizeof(addrinfo_request_t));
557 assert(length == sizeof(addrinfo_request_t) + ai_req->node_len + ai_req->service_len);
559 memset(&ai, 0, sizeof(ai));
560 ai.ai_flags = ai_req->ai_flags;
561 ai.ai_family = ai_req->ai_family;
562 ai.ai_socktype = ai_req->ai_socktype;
563 ai.ai_protocol = ai_req->ai_protocol;
565 node = ai_req->node_len ? (const char*) ai_req + sizeof(addrinfo_request_t) : NULL;
566 service = ai_req->service_len ? (const char*) ai_req + sizeof(addrinfo_request_t) + ai_req->node_len : NULL;
568 ret = getaddrinfo(node, service,
569 ai_req->hints_is_null ? NULL : &ai,
572 /* send_addrinfo_reply() frees result */
573 return send_addrinfo_reply(out_fd, req->id, ret, result, errno, h_errno);
576 case REQUEST_NAMEINFO: {
578 const nameinfo_request_t *ni_req = &packet->nameinfo_request;
579 char hostbuf[NI_MAXHOST], servbuf[NI_MAXSERV];
580 struct sockaddr_storage sa;
582 assert(length >= sizeof(nameinfo_request_t));
583 assert(length == sizeof(nameinfo_request_t) + ni_req->sockaddr_len);
585 memcpy(&sa, (const uint8_t *) ni_req + sizeof(nameinfo_request_t), ni_req->sockaddr_len);
587 ret = getnameinfo((struct sockaddr *)&sa, ni_req->sockaddr_len,
588 ni_req->gethost ? hostbuf : NULL, ni_req->gethost ? sizeof(hostbuf) : 0,
589 ni_req->getserv ? servbuf : NULL, ni_req->getserv ? sizeof(servbuf) : 0,
592 return send_nameinfo_reply(out_fd, req->id, ret,
593 ret == 0 && ni_req->gethost ? hostbuf : NULL,
594 ret == 0 && ni_req->getserv ? servbuf : NULL,
598 case REQUEST_RES_QUERY:
599 case REQUEST_RES_SEARCH: {
601 HEADER answer[BUFSIZE/sizeof(HEADER) + 1];
602 const res_request_t *res_req = &packet->res_request;
605 assert(length >= sizeof(res_request_t));
606 assert(length == sizeof(res_request_t) + res_req->dname_len);
608 dname = (const char *) req + sizeof(res_request_t);
610 if (req->type == REQUEST_RES_QUERY)
611 ret = res_query(dname, res_req->class, res_req->type, (unsigned char *) answer, BUFSIZE);
613 ret = res_search(dname, res_req->class, res_req->type, (unsigned char *) answer, BUFSIZE);
615 return send_res_reply(out_fd, req->id, (unsigned char *) answer, ret, errno, h_errno);
618 case REQUEST_TERMINATE:
631 static int process_worker(int in_fd, int out_fd) {
632 int have_death_sig = 0;
636 const int ignore_sigs[] = {
652 if (open("/dev/null", O_RDONLY) != 0)
655 if (open("/dev/null", O_WRONLY) != 1)
658 if (open("/dev/null", O_WRONLY) != 2)
664 if (geteuid() == 0) {
668 if ((pw = getpwnam("nobody"))) {
669 #ifdef HAVE_SETRESUID
670 r = setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid);
672 r = setreuid(pw->pw_uid, pw->pw_uid);
674 if ((r = setuid(pw->pw_uid)) >= 0)
675 r = seteuid(pw->pw_uid);
682 if (reset_sigsv(ignore_sigs) < 0)
685 if (ignore_sigsv(ignore_sigs) < 0)
688 good_fds[0] = in_fd; good_fds[1] = out_fd; good_fds[2] = -1;
689 if (close_allv(good_fds) < 0)
692 #ifdef PR_SET_PDEATHSIG
693 if (prctl(PR_SET_PDEATHSIG, SIGTERM) >= 0)
700 while (getppid() > 1) { /* if the parent PID is 1 our parent process died. */
701 packet_t buf[BUFSIZE/sizeof(packet_t) + 1];
704 if (!have_death_sig) {
706 struct timeval tv = { 0, 500000 };
711 if (select(in_fd+1, &fds, NULL, NULL, &tv) < 0)
718 if ((length = recv(in_fd, buf, sizeof(buf), 0)) <= 0) {
721 (errno == EAGAIN || errno == EINTR))
727 if (handle_request(out_fd, buf, (size_t) length) < 0)
741 static void* thread_worker(void *p) {
742 _g_asyncns_t *asyncns = p;
745 /* No signals in this thread please */
746 sigfillset(&fullset);
747 pthread_sigmask(SIG_BLOCK, &fullset, NULL);
749 while (!asyncns->dead) {
750 packet_t buf[BUFSIZE/sizeof(packet_t) + 1];
753 if ((length = recv(asyncns->fds[REQUEST_RECV_FD], buf, sizeof(buf), 0)) <= 0) {
756 (errno == EAGAIN || errno == EINTR))
765 if (handle_request(asyncns->fds[RESPONSE_SEND_FD], buf, (size_t) length) < 0)
769 send_died(asyncns->fds[RESPONSE_SEND_FD]);
776 _g_asyncns_t* _g_asyncns_new(unsigned n_proc) {
777 _g_asyncns_t *asyncns = NULL;
781 if (n_proc > MAX_WORKERS)
782 n_proc = MAX_WORKERS;
784 if (!(asyncns = malloc(sizeof(_g_asyncns_t)))) {
790 asyncns->valid_workers = 0;
792 for (i = 0; i < MESSAGE_FD_MAX; i++)
793 asyncns->fds[i] = -1;
795 memset(asyncns->queries, 0, sizeof(asyncns->queries));
797 if (socketpair(PF_UNIX, SOCK_DGRAM, 0, asyncns->fds) < 0 ||
798 socketpair(PF_UNIX, SOCK_DGRAM, 0, asyncns->fds+2) < 0)
801 for (i = 0; i < MESSAGE_FD_MAX; i++)
802 fd_cloexec(asyncns->fds[i]);
804 for (asyncns->valid_workers = 0; asyncns->valid_workers < n_proc; asyncns->valid_workers++) {
807 if ((asyncns->workers[asyncns->valid_workers] = fork()) < 0)
809 else if (asyncns->workers[asyncns->valid_workers] == 0) {
812 close(asyncns->fds[REQUEST_SEND_FD]);
813 close(asyncns->fds[RESPONSE_RECV_FD]);
814 ret = process_worker(asyncns->fds[REQUEST_RECV_FD], asyncns->fds[RESPONSE_SEND_FD]);
815 close(asyncns->fds[REQUEST_RECV_FD]);
816 close(asyncns->fds[RESPONSE_SEND_FD]);
822 if ((r = pthread_create(&asyncns->workers[asyncns->valid_workers], NULL, thread_worker, asyncns)) != 0) {
830 close(asyncns->fds[REQUEST_RECV_FD]);
831 close(asyncns->fds[RESPONSE_SEND_FD]);
832 asyncns->fds[REQUEST_RECV_FD] = asyncns->fds[RESPONSE_SEND_FD] = -1;
835 asyncns->current_index = asyncns->current_id = 0;
836 asyncns->done_head = asyncns->done_tail = NULL;
837 asyncns->n_queries = 0;
839 fd_nonblock(asyncns->fds[RESPONSE_RECV_FD]);
845 _g_asyncns_free(asyncns);
850 void _g_asyncns_free(_g_asyncns_t *asyncns) {
852 int saved_errno = errno;
859 if (asyncns->fds[REQUEST_SEND_FD] >= 0) {
862 memset(&req, 0, sizeof(req));
863 req.type = REQUEST_TERMINATE;
864 req.length = sizeof(req);
867 /* Send one termination packet for each worker */
868 for (p = 0; p < asyncns->valid_workers; p++)
869 send(asyncns->fds[REQUEST_SEND_FD], &req, req.length, MSG_NOSIGNAL);
872 /* Now terminate them and wait until they are gone. */
873 for (p = 0; p < asyncns->valid_workers; p++) {
875 kill(asyncns->workers[p], SIGTERM);
877 if (waitpid(asyncns->workers[p], NULL, 0) >= 0 || errno != EINTR)
882 if (pthread_join(asyncns->workers[p], NULL) != EINTR)
888 /* Close all communication channels */
889 for (i = 0; i < MESSAGE_FD_MAX; i++)
890 if (asyncns->fds[i] >= 0)
891 close(asyncns->fds[i]);
893 for (p = 0; p < MAX_QUERIES; p++)
894 if (asyncns->queries[p])
895 _g_asyncns_cancel(asyncns, asyncns->queries[p]);
902 int _g_asyncns_fd(_g_asyncns_t *asyncns) {
905 return asyncns->fds[RESPONSE_RECV_FD];
908 static _g_asyncns_query_t *lookup_query(_g_asyncns_t *asyncns, unsigned id) {
909 _g_asyncns_query_t *q;
912 if ((q = asyncns->queries[id % MAX_QUERIES]))
919 static void complete_query(_g_asyncns_t *asyncns, _g_asyncns_query_t *q) {
926 if ((q->done_prev = asyncns->done_tail))
927 asyncns->done_tail->done_next = q;
929 asyncns->done_head = q;
931 asyncns->done_tail = q;
935 static const void *unserialize_addrinfo(const void *p, struct addrinfo **ret_ai, size_t *length) {
936 addrinfo_serialization_t s;
943 if (*length < sizeof(addrinfo_serialization_t))
946 memcpy(&s, p, sizeof(s));
948 l = sizeof(addrinfo_serialization_t) + s.ai_addrlen + s.canonname_len;
952 if (!(ai = malloc(sizeof(struct addrinfo))))
956 ai->ai_canonname = NULL;
959 if (s.ai_addrlen && !(ai->ai_addr = malloc(s.ai_addrlen)))
962 if (s.canonname_len && !(ai->ai_canonname = malloc(s.canonname_len)))
965 ai->ai_flags = s.ai_flags;
966 ai->ai_family = s.ai_family;
967 ai->ai_socktype = s.ai_socktype;
968 ai->ai_protocol = s.ai_protocol;
969 ai->ai_addrlen = s.ai_addrlen;
972 memcpy(ai->ai_addr, (const uint8_t*) p + sizeof(addrinfo_serialization_t), s.ai_addrlen);
974 if (ai->ai_canonname)
975 memcpy(ai->ai_canonname, (const uint8_t*) p + sizeof(addrinfo_serialization_t) + s.ai_addrlen, s.canonname_len);
980 return (const uint8_t*) p + l;
985 _g_asyncns_freeaddrinfo(ai);
990 static int handle_response(_g_asyncns_t *asyncns, const packet_t *packet, size_t length) {
991 const rheader_t *resp;
992 _g_asyncns_query_t *q;
996 resp = &packet->rheader;
998 assert(length >= sizeof(rheader_t));
999 assert(length == resp->length);
1001 if (resp->type == RESPONSE_DIED) {
1006 if (!(q = lookup_query(asyncns, resp->id)))
1009 switch (resp->type) {
1010 case RESPONSE_ADDRINFO: {
1011 const addrinfo_response_t *ai_resp = &packet->addrinfo_response;
1014 struct addrinfo *prev = NULL;
1016 assert(length >= sizeof(addrinfo_response_t));
1017 assert(q->type == REQUEST_ADDRINFO);
1019 q->ret = ai_resp->ret;
1020 q->_errno = ai_resp->_errno;
1021 q->_h_errno = ai_resp->_h_errno;
1022 l = length - sizeof(addrinfo_response_t);
1023 p = (const uint8_t*) resp + sizeof(addrinfo_response_t);
1025 while (l > 0 && p) {
1026 struct addrinfo *ai = NULL;
1027 p = unserialize_addrinfo(p, &ai, &l);
1030 q->ret = EAI_MEMORY;
1042 complete_query(asyncns, q);
1046 case RESPONSE_NAMEINFO: {
1047 const nameinfo_response_t *ni_resp = &packet->nameinfo_response;
1049 assert(length >= sizeof(nameinfo_response_t));
1050 assert(q->type == REQUEST_NAMEINFO);
1052 q->ret = ni_resp->ret;
1053 q->_errno = ni_resp->_errno;
1054 q->_h_errno = ni_resp->_h_errno;
1056 if (ni_resp->hostlen)
1057 if (!(q->host = strndup((const char*) ni_resp + sizeof(nameinfo_response_t), ni_resp->hostlen-1)))
1058 q->ret = EAI_MEMORY;
1060 if (ni_resp->servlen)
1061 if (!(q->serv = strndup((const char*) ni_resp + sizeof(nameinfo_response_t) + ni_resp->hostlen, ni_resp->servlen-1)))
1062 q->ret = EAI_MEMORY;
1064 complete_query(asyncns, q);
1068 case RESPONSE_RES: {
1069 const res_response_t *res_resp = &packet->res_response;
1071 assert(length >= sizeof(res_response_t));
1072 assert(q->type == REQUEST_RES_QUERY || q->type == REQUEST_RES_SEARCH);
1074 q->ret = res_resp->ret;
1075 q->_errno = res_resp->_errno;
1076 q->_h_errno = res_resp->_h_errno;
1078 if (res_resp->ret >= 0) {
1079 if (!(q->serv = malloc(res_resp->ret))) {
1083 memcpy(q->serv, (const char *)resp + sizeof(res_response_t), res_resp->ret);
1086 complete_query(asyncns, q);
1097 int _g_asyncns_wait(_g_asyncns_t *asyncns, int block) {
1102 packet_t buf[BUFSIZE/sizeof(packet_t) + 1];
1105 if (asyncns->dead) {
1110 if (((l = recv(asyncns->fds[RESPONSE_RECV_FD], buf, sizeof(buf), 0)) < 0)) {
1113 if (errno != EAGAIN)
1116 if (!block || handled)
1120 FD_SET(asyncns->fds[RESPONSE_RECV_FD], &fds);
1122 if (select(asyncns->fds[RESPONSE_RECV_FD]+1, &fds, NULL, NULL, NULL) < 0)
1128 if (handle_response(asyncns, buf, (size_t) l) < 0)
1135 static _g_asyncns_query_t *alloc_query(_g_asyncns_t *asyncns) {
1136 _g_asyncns_query_t *q;
1139 if (asyncns->n_queries >= MAX_QUERIES) {
1144 while (asyncns->queries[asyncns->current_index]) {
1146 asyncns->current_index++;
1147 asyncns->current_id++;
1149 while (asyncns->current_index >= MAX_QUERIES)
1150 asyncns->current_index -= MAX_QUERIES;
1153 if (!(q = asyncns->queries[asyncns->current_index] = malloc(sizeof(_g_asyncns_query_t)))) {
1158 asyncns->n_queries++;
1160 q->asyncns = asyncns;
1162 q->id = asyncns->current_id;
1163 q->done_next = q->done_prev = NULL;
1169 q->host = q->serv = NULL;
1174 _g_asyncns_query_t* _g_asyncns_getaddrinfo(_g_asyncns_t *asyncns, const char *node, const char *service, const struct addrinfo *hints) {
1175 addrinfo_request_t data[BUFSIZE/sizeof(addrinfo_request_t) + 1];
1176 addrinfo_request_t *req = data;
1177 _g_asyncns_query_t *q;
1179 assert(node || service);
1181 if (asyncns->dead) {
1186 if (!(q = alloc_query(asyncns)))
1189 memset(req, 0, sizeof(addrinfo_request_t));
1191 req->node_len = node ? strlen(node)+1 : 0;
1192 req->service_len = service ? strlen(service)+1 : 0;
1194 req->header.id = q->id;
1195 req->header.type = q->type = REQUEST_ADDRINFO;
1196 req->header.length = sizeof(addrinfo_request_t) + req->node_len + req->service_len;
1198 if (req->header.length > BUFSIZE) {
1203 if (!(req->hints_is_null = !hints)) {
1204 req->ai_flags = hints->ai_flags;
1205 req->ai_family = hints->ai_family;
1206 req->ai_socktype = hints->ai_socktype;
1207 req->ai_protocol = hints->ai_protocol;
1211 strcpy((char*) req + sizeof(addrinfo_request_t), node);
1214 strcpy((char*) req + sizeof(addrinfo_request_t) + req->node_len, service);
1216 if (send(asyncns->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0)
1223 _g_asyncns_cancel(asyncns, q);
1228 int _g_asyncns_getaddrinfo_done(_g_asyncns_t *asyncns, _g_asyncns_query_t* q, struct addrinfo **ret_res) {
1232 assert(q->asyncns == asyncns);
1233 assert(q->type == REQUEST_ADDRINFO);
1235 if (asyncns->dead) {
1243 *ret_res = q->addrinfo;
1248 if (ret == EAI_SYSTEM)
1252 h_errno = q->_h_errno;
1254 _g_asyncns_cancel(asyncns, q);
1259 _g_asyncns_query_t* _g_asyncns_getnameinfo(_g_asyncns_t *asyncns, const struct sockaddr *sa, socklen_t salen, int flags, int gethost, int getserv) {
1260 nameinfo_request_t data[BUFSIZE/sizeof(nameinfo_request_t) + 1];
1261 nameinfo_request_t *req = data;
1262 _g_asyncns_query_t *q;
1268 if (asyncns->dead) {
1273 if (!(q = alloc_query(asyncns)))
1276 memset(req, 0, sizeof(nameinfo_request_t));
1278 req->header.id = q->id;
1279 req->header.type = q->type = REQUEST_NAMEINFO;
1280 req->header.length = sizeof(nameinfo_request_t) + salen;
1282 if (req->header.length > BUFSIZE) {
1288 req->sockaddr_len = salen;
1289 req->gethost = gethost;
1290 req->getserv = getserv;
1292 memcpy((uint8_t*) req + sizeof(nameinfo_request_t), sa, salen);
1294 if (send(asyncns->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0)
1301 _g_asyncns_cancel(asyncns, q);
1306 int _g_asyncns_getnameinfo_done(_g_asyncns_t *asyncns, _g_asyncns_query_t* q, char *ret_host, size_t hostlen, char *ret_serv, size_t servlen) {
1310 assert(q->asyncns == asyncns);
1311 assert(q->type == REQUEST_NAMEINFO);
1312 assert(!ret_host || hostlen);
1313 assert(!ret_serv || servlen);
1315 if (asyncns->dead) {
1323 if (ret_host && q->host) {
1324 strncpy(ret_host, q->host, hostlen);
1325 ret_host[hostlen-1] = 0;
1328 if (ret_serv && q->serv) {
1329 strncpy(ret_serv, q->serv, servlen);
1330 ret_serv[servlen-1] = 0;
1335 if (ret == EAI_SYSTEM)
1339 h_errno = q->_h_errno;
1341 _g_asyncns_cancel(asyncns, q);
1346 static _g_asyncns_query_t * _g_asyncns_res(_g_asyncns_t *asyncns, query_type_t qtype, const char *dname, int class, int type) {
1347 res_request_t data[BUFSIZE/sizeof(res_request_t) + 1];
1348 res_request_t *req = data;
1349 _g_asyncns_query_t *q;
1354 if (asyncns->dead) {
1359 if (!(q = alloc_query(asyncns)))
1362 memset(req, 0, sizeof(res_request_t));
1364 req->dname_len = strlen(dname) + 1;
1366 req->header.id = q->id;
1367 req->header.type = q->type = qtype;
1368 req->header.length = sizeof(res_request_t) + req->dname_len;
1370 if (req->header.length > BUFSIZE) {
1378 strcpy((char*) req + sizeof(res_request_t), dname);
1380 if (send(asyncns->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0)
1387 _g_asyncns_cancel(asyncns, q);
1392 _g_asyncns_query_t* _g_asyncns_res_query(_g_asyncns_t *asyncns, const char *dname, int class, int type) {
1393 return _g_asyncns_res(asyncns, REQUEST_RES_QUERY, dname, class, type);
1396 _g_asyncns_query_t* _g_asyncns_res_search(_g_asyncns_t *asyncns, const char *dname, int class, int type) {
1397 return _g_asyncns_res(asyncns, REQUEST_RES_SEARCH, dname, class, type);
1400 int _g_asyncns_res_done(_g_asyncns_t *asyncns, _g_asyncns_query_t* q, unsigned char **answer) {
1404 assert(q->asyncns == asyncns);
1405 assert(q->type == REQUEST_RES_QUERY || q->type == REQUEST_RES_SEARCH);
1408 if (asyncns->dead) {
1418 *answer = (unsigned char *)q->serv;
1425 h_errno = q->_h_errno;
1428 _g_asyncns_cancel(asyncns, q);
1430 return ret < 0 ? -errno : ret;
1433 _g_asyncns_query_t* _g_asyncns_getnext(_g_asyncns_t *asyncns) {
1435 return asyncns->done_head;
1438 int _g_asyncns_getnqueries(_g_asyncns_t *asyncns) {
1440 return asyncns->n_queries;
1443 void _g_asyncns_cancel(_g_asyncns_t *asyncns, _g_asyncns_query_t* q) {
1445 int saved_errno = errno;
1449 assert(q->asyncns == asyncns);
1450 assert(asyncns->n_queries > 0);
1455 q->done_prev->done_next = q->done_next;
1457 asyncns->done_head = q->done_next;
1460 q->done_next->done_prev = q->done_prev;
1462 asyncns->done_tail = q->done_prev;
1465 i = q->id % MAX_QUERIES;
1466 assert(asyncns->queries[i] == q);
1467 asyncns->queries[i] = NULL;
1469 _g_asyncns_freeaddrinfo(q->addrinfo);
1473 asyncns->n_queries--;
1476 errno = saved_errno;
1479 void _g_asyncns_freeaddrinfo(struct addrinfo *ai) {
1480 int saved_errno = errno;
1483 struct addrinfo *next = ai->ai_next;
1486 free(ai->ai_canonname);
1492 errno = saved_errno;
1495 void _g_asyncns_freeanswer(unsigned char *answer) {
1496 int saved_errno = errno;
1501 /* Please note that this function is new in libasyncns 0.4. In
1502 * older versions you were supposed to free the answer directly
1503 * with free(). Hence, if this function is changed to do more than
1504 * just a simple free() this must be considered ABI/API breakage! */
1508 errno = saved_errno;
1511 int _g_asyncns_isdone(_g_asyncns_t *asyncns, _g_asyncns_query_t*q) {
1514 assert(q->asyncns == asyncns);
1519 void _g_asyncns_setuserdata(_g_asyncns_t *asyncns, _g_asyncns_query_t *q, void *userdata) {
1522 assert(q->asyncns = asyncns);
1524 q->userdata = userdata;
1527 void* _g_asyncns_getuserdata(_g_asyncns_t *asyncns, _g_asyncns_query_t *q) {
1530 assert(q->asyncns = asyncns);