chiark / gitweb /
sd-dns: initial commit
[elogind.git] / src / libsystemd-bus / sd-dns.c
1 /***
2   This file is part of libasyncns.
3
4   Copyright 2005-2008 Lennart Poettering
5
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.
10
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.
15
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/>.
19  ***/
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <assert.h>
26 #include <fcntl.h>
27 #include <signal.h>
28 #include <unistd.h>
29 #include <sys/select.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <errno.h>
34 #include <sys/wait.h>
35 #include <sys/types.h>
36 #include <pwd.h>
37 #include <netinet/in.h>
38 #include <arpa/nameser.h>
39 #include <resolv.h>
40 #include <dirent.h>
41 #include <sys/time.h>
42 #include <sys/resource.h>
43 #include <stdint.h>
44 #include <pthread.h>
45
46 #ifdef HAVE_SYS_PRCTL_H
47 #include <sys/prctl.h>
48 #endif
49
50 #include "sd-dns.h"
51 #include "util.h"
52
53 #define MAX_WORKERS 16
54 #define MAX_QUERIES 256
55 #define BUFSIZE (10240)
56
57 typedef enum {
58         REQUEST_ADDRINFO,
59         RESPONSE_ADDRINFO,
60         REQUEST_NAMEINFO,
61         RESPONSE_NAMEINFO,
62         REQUEST_RES_QUERY,
63         REQUEST_RES_SEARCH,
64         RESPONSE_RES,
65         REQUEST_TERMINATE,
66         RESPONSE_DIED
67 } query_type_t;
68
69 enum {
70         REQUEST_RECV_FD = 0,
71         REQUEST_SEND_FD = 1,
72         RESPONSE_RECV_FD = 2,
73         RESPONSE_SEND_FD = 3,
74         MESSAGE_FD_MAX = 4
75 };
76
77 struct asyncns {
78         int fds[MESSAGE_FD_MAX];
79
80         pthread_t workers[MAX_WORKERS];
81         unsigned valid_workers;
82
83         unsigned current_id, current_index;
84         asyncns_query_t* queries[MAX_QUERIES];
85
86         asyncns_query_t *done_head, *done_tail;
87
88         int n_queries;
89         int dead;
90 };
91
92 struct asyncns_query {
93         asyncns_t *asyncns;
94         int done;
95         unsigned id;
96         query_type_t type;
97         asyncns_query_t *done_next, *done_prev;
98         int ret;
99         int _errno;
100         int _h_errno;
101         struct addrinfo *addrinfo;
102         char *serv, *host;
103         void *userdata;
104 };
105
106 typedef struct rheader {
107         query_type_t type;
108         unsigned id;
109         size_t length;
110 } rheader_t;
111
112 typedef struct addrinfo_request {
113         struct rheader header;
114         int hints_is_null;
115         int ai_flags;
116         int ai_family;
117         int ai_socktype;
118         int ai_protocol;
119         size_t node_len, service_len;
120 } addrinfo_request_t;
121
122 typedef struct addrinfo_response {
123         struct rheader header;
124         int ret;
125         int _errno;
126         int _h_errno;
127         /* followed by addrinfo_serialization[] */
128 } addrinfo_response_t;
129
130 typedef struct addrinfo_serialization {
131         int ai_flags;
132         int ai_family;
133         int ai_socktype;
134         int ai_protocol;
135         size_t ai_addrlen;
136         size_t canonname_len;
137         /* Followed by ai_addr amd ai_canonname with variable lengths */
138 } addrinfo_serialization_t;
139
140 typedef struct nameinfo_request {
141         struct rheader header;
142         int flags;
143         socklen_t sockaddr_len;
144         int gethost, getserv;
145 } nameinfo_request_t;
146
147 typedef struct nameinfo_response {
148         struct rheader header;
149         size_t hostlen, servlen;
150         int ret;
151         int _errno;
152         int _h_errno;
153 } nameinfo_response_t;
154
155 typedef struct res_request {
156         struct rheader header;
157         int class;
158         int type;
159         size_t dname_len;
160 } res_request_t;
161
162 typedef struct res_response {
163         struct rheader header;
164         int ret;
165         int _errno;
166         int _h_errno;
167 } res_response_t;
168
169 typedef union packet {
170         rheader_t rheader;
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;
177 } packet_t;
178
179 static int send_died(int out_fd) {
180         rheader_t rh = {};
181         assert(out_fd > 0);
182
183         rh.type = RESPONSE_DIED;
184         rh.id = 0;
185         rh.length = sizeof(rh);
186
187         return send(out_fd, &rh, rh.length, MSG_NOSIGNAL);
188 }
189
190 static void *serialize_addrinfo(void *p, const struct addrinfo *ai, size_t *length, size_t maxlength) {
191         addrinfo_serialization_t s;
192         size_t cnl, l;
193         assert(p);
194         assert(ai);
195         assert(length);
196         assert(*length <= maxlength);
197
198         cnl = (ai->ai_canonname ? strlen(ai->ai_canonname)+1 : 0);
199         l = sizeof(addrinfo_serialization_t) + ai->ai_addrlen + cnl;
200
201         if (*length + l > maxlength)
202                 return NULL;
203
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;
210
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);
213
214         if (ai->ai_canonname)
215                 strcpy((char*) p + sizeof(addrinfo_serialization_t) + ai->ai_addrlen, ai->ai_canonname);
216
217         *length += l;
218         return (uint8_t*) p + l;
219 }
220
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;
224         assert(out_fd >= 0);
225
226         resp->header.type = RESPONSE_ADDRINFO;
227         resp->header.id = id;
228         resp->header.length = sizeof(addrinfo_response_t);
229         resp->ret = ret;
230         resp->_errno = _errno;
231         resp->_h_errno = _h_errno;
232
233         if (ret == 0 && ai) {
234                 void *p = data + 1;
235                 struct addrinfo *k;
236
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;
240                                 break;
241                         }
242                 }
243         }
244
245         if (ai)
246                 freeaddrinfo(ai);
247
248         return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL);
249 }
250
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] = {};
253         size_t hl, sl;
254         nameinfo_response_t *resp = data;
255
256         assert(out_fd >= 0);
257
258         sl = serv ? strlen(serv)+1 : 0;
259         hl = host ? strlen(host)+1 : 0;
260
261         resp->header.type = RESPONSE_NAMEINFO;
262         resp->header.id = id;
263         resp->header.length = sizeof(nameinfo_response_t) + hl + sl;
264         resp->ret = ret;
265         resp->_errno = _errno;
266         resp->_h_errno = _h_errno;
267         resp->hostlen = hl;
268         resp->servlen = sl;
269
270         assert(sizeof(data) >= resp->header.length);
271
272         if (host)
273                 memcpy((uint8_t *)data + sizeof(nameinfo_response_t), host, hl);
274
275         if (serv)
276                 memcpy((uint8_t *)data + sizeof(nameinfo_response_t) + hl, serv, sl);
277
278         return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL);
279 }
280
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;
284
285         assert(out_fd >= 0);
286
287         resp->header.type = RESPONSE_RES;
288         resp->header.id = id;
289         resp->header.length = sizeof(res_response_t) + (ret < 0 ? 0 : ret);
290         resp->ret = ret;
291         resp->_errno = _errno;
292         resp->_h_errno = _h_errno;
293
294         assert(sizeof(data) >= resp->header.length);
295
296         if (ret > 0)
297                 memcpy((uint8_t *)data + sizeof(res_response_t), answer, ret);
298
299         return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL);
300 }
301
302 static int handle_request(int out_fd, const packet_t *packet, size_t length) {
303         const rheader_t *req;
304         assert(out_fd >= 0);
305
306         req = &packet->rheader;
307         assert(req);
308         assert(length >= sizeof(rheader_t));
309         assert(length == req->length);
310
311         switch (req->type) {
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;
316                int ret;
317
318                assert(length >= sizeof(addrinfo_request_t));
319                assert(length == sizeof(addrinfo_request_t) + ai_req->node_len + ai_req->service_len);
320
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;
325
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;
328
329                ret = getaddrinfo(node, service,
330                                ai_req->hints_is_null ? NULL : &ai,
331                                &result);
332
333                /* send_addrinfo_reply() frees result */
334                return send_addrinfo_reply(out_fd, req->id, ret, result, errno, h_errno);
335         }
336
337         case REQUEST_NAMEINFO: {
338                int ret;
339                const nameinfo_request_t *ni_req = &packet->nameinfo_request;
340                char hostbuf[NI_MAXHOST], servbuf[NI_MAXSERV];
341                struct sockaddr_storage sa;
342
343                assert(length >= sizeof(nameinfo_request_t));
344                assert(length == sizeof(nameinfo_request_t) + ni_req->sockaddr_len);
345
346                memcpy(&sa, (const uint8_t *) ni_req + sizeof(nameinfo_request_t), ni_req->sockaddr_len);
347
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,
351                                ni_req->flags);
352
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,
356                                errno, h_errno);
357         }
358
359         case REQUEST_RES_QUERY:
360         case REQUEST_RES_SEARCH: {
361                  int ret;
362                  HEADER answer[BUFSIZE/sizeof(HEADER) + 1];
363                  const res_request_t *res_req = &packet->res_request;
364                  const char *dname;
365
366                  assert(length >= sizeof(res_request_t));
367                  assert(length == sizeof(res_request_t) + res_req->dname_len);
368
369                  dname = (const char *) req + sizeof(res_request_t);
370
371                  if (req->type == REQUEST_RES_QUERY)
372                          ret = res_query(dname, res_req->class, res_req->type, (unsigned char *) answer, BUFSIZE);
373                  else
374                          ret = res_search(dname, res_req->class, res_req->type, (unsigned char *) answer, BUFSIZE);
375
376                  return send_res_reply(out_fd, req->id, (unsigned char *) answer, ret, errno, h_errno);
377         }
378
379         case REQUEST_TERMINATE:
380                  /* Quit */
381                  return -1;
382
383         default:
384                  ;
385         }
386
387         return 0;
388 }
389
390 static void* thread_worker(void *p) {
391         asyncns_t *asyncns = p;
392         sigset_t fullset;
393
394         /* No signals in this thread please */
395         sigfillset(&fullset);
396         pthread_sigmask(SIG_BLOCK, &fullset, NULL);
397
398         while (!asyncns->dead) {
399                 packet_t buf[BUFSIZE/sizeof(packet_t) + 1];
400                 ssize_t length;
401
402                 length = recv(asyncns->fds[REQUEST_RECV_FD], buf, sizeof(buf), 0);
403
404                 if (length <= 0) {
405                         if (length < 0 && (errno == EAGAIN || errno == EINTR))
406                                 continue;
407                         break;
408                 }
409
410                 if (asyncns->dead)
411                         break;
412
413                 if (handle_request(asyncns->fds[RESPONSE_SEND_FD], buf, (size_t) length) < 0)
414                         break;
415         }
416
417         send_died(asyncns->fds[RESPONSE_SEND_FD]);
418
419         return NULL;
420 }
421
422 asyncns_t* asyncns_new(unsigned n_proc) {
423         int i;
424         asyncns_t *asyncns = NULL;
425
426         assert(n_proc >= 1);
427
428         if (n_proc > MAX_WORKERS)
429                 n_proc = MAX_WORKERS;
430
431         asyncns = malloc(sizeof(asyncns_t));
432         if (!asyncns) {
433                 errno = ENOMEM;
434                 goto fail;
435         }
436
437         asyncns->dead = 0;
438         asyncns->valid_workers = 0;
439
440         for (i = 0; i < MESSAGE_FD_MAX; i++)
441                 asyncns->fds[i] = -1;
442
443         memset(asyncns->queries, 0, sizeof(asyncns->queries));
444
445 #ifdef SOCK_CLOEXEC
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) {
448
449                 /* Try again, without SOCK_CLOEXEC */
450                 if (errno == EINVAL) {
451 #endif
452                         if (socketpair(PF_UNIX, SOCK_DGRAM, 0, asyncns->fds) < 0 ||
453                                         socketpair(PF_UNIX, SOCK_DGRAM, 0, asyncns->fds+2) < 0)
454                                 goto fail;
455 #ifdef SOCK_CLOEXEC
456                 } else
457                         goto fail;
458         }
459 #endif
460
461         for (i = 0; i < MESSAGE_FD_MAX; i++)
462                 fd_cloexec(asyncns->fds[i], true);
463
464         for (asyncns->valid_workers = 0; asyncns->valid_workers < n_proc; asyncns->valid_workers++) {
465                 int r;
466
467                 if ((r = pthread_create(&asyncns->workers[asyncns->valid_workers], NULL, thread_worker, asyncns)) != 0) {
468                         errno = r;
469                         goto fail;
470                 }
471         }
472
473         asyncns->current_index = asyncns->current_id = 0;
474         asyncns->done_head = asyncns->done_tail = NULL;
475         asyncns->n_queries = 0;
476
477         fd_nonblock(asyncns->fds[RESPONSE_RECV_FD], true);
478
479         return asyncns;
480
481 fail:
482         if (asyncns)
483                 asyncns_free(asyncns);
484
485         return NULL;
486 }
487
488 void asyncns_free(asyncns_t *asyncns) {
489         int i;
490         int saved_errno = errno;
491         unsigned p;
492
493         assert(asyncns);
494
495         asyncns->dead = 1;
496
497         if (asyncns->fds[REQUEST_SEND_FD] >= 0) {
498                 rheader_t req = {};
499
500                 req.type = REQUEST_TERMINATE;
501                 req.length = sizeof(req);
502                 req.id = 0;
503
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);
507         }
508
509         /* Now terminate them and wait until they are gone. */
510         for (p = 0; p < asyncns->valid_workers; p++) {
511                 for (;;) {
512                         if (pthread_join(asyncns->workers[p], NULL) != EINTR)
513                                 break;
514                 }
515         }
516
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]);
521
522         for (p = 0; p < MAX_QUERIES; p++)
523                 if (asyncns->queries[p])
524                         asyncns_cancel(asyncns, asyncns->queries[p]);
525
526         free(asyncns);
527
528         errno = saved_errno;
529 }
530
531 int asyncns_fd(asyncns_t *asyncns) {
532         assert(asyncns);
533
534         return asyncns->fds[RESPONSE_RECV_FD];
535 }
536
537 static asyncns_query_t *lookup_query(asyncns_t *asyncns, unsigned id) {
538         asyncns_query_t *q;
539         assert(asyncns);
540
541         if ((q = asyncns->queries[id % MAX_QUERIES]))
542                 if (q->id == id)
543                         return q;
544
545         return NULL;
546 }
547
548 static void complete_query(asyncns_t *asyncns, asyncns_query_t *q) {
549         assert(asyncns);
550         assert(q);
551         assert(!q->done);
552
553         q->done = 1;
554
555         if ((q->done_prev = asyncns->done_tail))
556                 asyncns->done_tail->done_next = q;
557         else
558                 asyncns->done_head = q;
559
560         asyncns->done_tail = q;
561         q->done_next = NULL;
562 }
563
564 static const void *unserialize_addrinfo(const void *p, struct addrinfo **ret_ai, size_t *length) {
565         addrinfo_serialization_t s;
566         size_t l;
567         struct addrinfo *ai;
568         assert(p);
569         assert(ret_ai);
570         assert(length);
571
572         if (*length < sizeof(addrinfo_serialization_t))
573                 return NULL;
574
575         memcpy(&s, p, sizeof(s));
576
577         l = sizeof(addrinfo_serialization_t) + s.ai_addrlen + s.canonname_len;
578         if (*length < l)
579                 return NULL;
580
581         if (!(ai = malloc(sizeof(struct addrinfo))))
582                 goto fail;
583
584         ai->ai_addr = NULL;
585         ai->ai_canonname = NULL;
586         ai->ai_next = NULL;
587
588         if (s.ai_addrlen && !(ai->ai_addr = malloc(s.ai_addrlen)))
589                 goto fail;
590
591         if (s.canonname_len && !(ai->ai_canonname = malloc(s.canonname_len)))
592                 goto fail;
593
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;
599
600         if (ai->ai_addr)
601                 memcpy(ai->ai_addr, (const uint8_t*) p + sizeof(addrinfo_serialization_t), s.ai_addrlen);
602
603         if (ai->ai_canonname)
604                 memcpy(ai->ai_canonname, (const uint8_t*) p + sizeof(addrinfo_serialization_t) + s.ai_addrlen, s.canonname_len);
605
606         *length -= l;
607         *ret_ai = ai;
608
609         return (const uint8_t*) p + l;
610
611
612 fail:
613         if (ai)
614                 asyncns_freeaddrinfo(ai);
615
616         return NULL;
617 }
618
619 static int handle_response(asyncns_t *asyncns, const packet_t *packet, size_t length) {
620         const rheader_t *resp;
621         asyncns_query_t *q;
622
623         assert(asyncns);
624
625         resp = &packet->rheader;
626         assert(resp);
627         assert(length >= sizeof(rheader_t));
628         assert(length == resp->length);
629
630         if (resp->type == RESPONSE_DIED) {
631                 asyncns->dead = 1;
632                 return 0;
633         }
634
635         if (!(q = lookup_query(asyncns, resp->id)))
636                 return 0;
637
638         switch (resp->type) {
639         case RESPONSE_ADDRINFO: {
640                 const addrinfo_response_t *ai_resp = &packet->addrinfo_response;
641                 const void *p;
642                 size_t l;
643                 struct addrinfo *prev = NULL;
644
645                 assert(length >= sizeof(addrinfo_response_t));
646                 assert(q->type == REQUEST_ADDRINFO);
647
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);
653
654                 while (l > 0 && p) {
655                         struct addrinfo *ai = NULL;
656                         p = unserialize_addrinfo(p, &ai, &l);
657
658                         if (!p || !ai) {
659                                 q->ret = EAI_MEMORY;
660                                 break;
661                         }
662
663                         if (prev)
664                                 prev->ai_next = ai;
665                         else
666                                 q->addrinfo = ai;
667
668                         prev = ai;
669                 }
670
671                 complete_query(asyncns, q);
672                 break;
673         }
674
675         case RESPONSE_NAMEINFO: {
676                 const nameinfo_response_t *ni_resp = &packet->nameinfo_response;
677
678                 assert(length >= sizeof(nameinfo_response_t));
679                 assert(q->type == REQUEST_NAMEINFO);
680
681                 q->ret = ni_resp->ret;
682                 q->_errno = ni_resp->_errno;
683                 q->_h_errno = ni_resp->_h_errno;
684
685                 if (ni_resp->hostlen)
686                         if (!(q->host = strndup((const char*) ni_resp + sizeof(nameinfo_response_t), ni_resp->hostlen-1)))
687                                 q->ret = EAI_MEMORY;
688
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)))
691                                 q->ret = EAI_MEMORY;
692
693                 complete_query(asyncns, q);
694                 break;
695         }
696
697         case RESPONSE_RES: {
698                 const res_response_t *res_resp = &packet->res_response;
699
700                 assert(length >= sizeof(res_response_t));
701                 assert(q->type == REQUEST_RES_QUERY || q->type == REQUEST_RES_SEARCH);
702
703                 q->ret = res_resp->ret;
704                 q->_errno = res_resp->_errno;
705                 q->_h_errno = res_resp->_h_errno;
706
707                 if (res_resp->ret >= 0)  {
708                         if (!(q->serv = malloc(res_resp->ret))) {
709                                 q->ret = -1;
710                                 q->_errno = ENOMEM;
711                         } else
712                                 memcpy(q->serv, (const char *)resp + sizeof(res_response_t), res_resp->ret);
713                 }
714
715                 complete_query(asyncns, q);
716                 break;
717         }
718
719         default:
720                 ;
721         }
722
723         return 0;
724 }
725
726 int asyncns_wait(asyncns_t *asyncns, int block) {
727         int handled = 0;
728         assert(asyncns);
729
730         for (;;) {
731                 packet_t buf[BUFSIZE/sizeof(packet_t) + 1];
732                 ssize_t l;
733
734                 if (asyncns->dead) {
735                         errno = ECHILD;
736                         return -1;
737                 }
738
739                 if (((l = recv(asyncns->fds[RESPONSE_RECV_FD], buf, sizeof(buf), 0)) < 0)) {
740                         fd_set fds;
741
742                         if (errno != EAGAIN)
743                                 return -1;
744
745                         if (!block || handled)
746                                 return 0;
747
748                         FD_ZERO(&fds);
749                         FD_SET(asyncns->fds[RESPONSE_RECV_FD], &fds);
750
751                         if (select(asyncns->fds[RESPONSE_RECV_FD]+1, &fds, NULL, NULL, NULL) < 0)
752                                 return -1;
753
754                         continue;
755                 }
756
757                 if (handle_response(asyncns, buf, (size_t) l) < 0)
758                         return -1;
759
760                 handled = 1;
761         }
762 }
763
764 static asyncns_query_t *alloc_query(asyncns_t *asyncns) {
765         asyncns_query_t *q;
766         assert(asyncns);
767
768         if (asyncns->n_queries >= MAX_QUERIES) {
769                 errno = ENOMEM;
770                 return NULL;
771         }
772
773         while (asyncns->queries[asyncns->current_index]) {
774
775                 asyncns->current_index++;
776                 asyncns->current_id++;
777
778                 while (asyncns->current_index >= MAX_QUERIES)
779                         asyncns->current_index -= MAX_QUERIES;
780         }
781
782         if (!(q = asyncns->queries[asyncns->current_index] = malloc(sizeof(asyncns_query_t)))) {
783                 errno = ENOMEM;
784                 return NULL;
785         }
786
787         asyncns->n_queries++;
788
789         q->asyncns = asyncns;
790         q->done = 0;
791         q->id = asyncns->current_id;
792         q->done_next = q->done_prev = NULL;
793         q->ret = 0;
794         q->_errno = 0;
795         q->_h_errno = 0;
796         q->addrinfo = NULL;
797         q->userdata = NULL;
798         q->host = q->serv = NULL;
799
800         return q;
801 }
802
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;
806         asyncns_query_t *q;
807         assert(asyncns);
808         assert(node || service);
809
810         if (asyncns->dead) {
811                 errno = ECHILD;
812                 return NULL;
813         }
814
815         if (!(q = alloc_query(asyncns)))
816                 return NULL;
817
818
819         req->node_len = node ? strlen(node)+1 : 0;
820         req->service_len = service ? strlen(service)+1 : 0;
821
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;
825
826         if (req->header.length > BUFSIZE) {
827                 errno = ENOMEM;
828                 goto fail;
829         }
830
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;
836         }
837
838         if (node)
839                 strcpy((char*) req + sizeof(addrinfo_request_t), node);
840
841         if (service)
842                 strcpy((char*) req + sizeof(addrinfo_request_t) + req->node_len, service);
843
844         if (send(asyncns->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0)
845                 goto fail;
846
847         return q;
848
849 fail:
850         if (q)
851                 asyncns_cancel(asyncns, q);
852
853         return NULL;
854 }
855
856 int asyncns_getaddrinfo_done(asyncns_t *asyncns, asyncns_query_t* q, struct addrinfo **ret_res) {
857         int ret;
858         assert(asyncns);
859         assert(q);
860         assert(q->asyncns == asyncns);
861         assert(q->type == REQUEST_ADDRINFO);
862
863         if (asyncns->dead) {
864                 errno = ECHILD;
865                 return EAI_SYSTEM;
866         }
867
868         if (!q->done)
869                 return EAI_AGAIN;
870
871         *ret_res = q->addrinfo;
872         q->addrinfo = NULL;
873
874         ret = q->ret;
875
876         if (ret == EAI_SYSTEM)
877                 errno = q->_errno;
878
879         if (ret != 0)
880                 h_errno = q->_h_errno;
881
882         asyncns_cancel(asyncns, q);
883
884         return ret;
885 }
886
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;
890         asyncns_query_t *q;
891
892         assert(asyncns);
893         assert(sa);
894         assert(salen > 0);
895
896         if (asyncns->dead) {
897                 errno = ECHILD;
898                 return NULL;
899         }
900
901         if (!(q = alloc_query(asyncns)))
902                 return NULL;
903
904
905         req->header.id = q->id;
906         req->header.type = q->type = REQUEST_NAMEINFO;
907         req->header.length = sizeof(nameinfo_request_t) + salen;
908
909         if (req->header.length > BUFSIZE) {
910                 errno = ENOMEM;
911                 goto fail;
912         }
913
914         req->flags = flags;
915         req->sockaddr_len = salen;
916         req->gethost = gethost;
917         req->getserv = getserv;
918
919         memcpy((uint8_t*) req + sizeof(nameinfo_request_t), sa, salen);
920
921         if (send(asyncns->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0)
922                 goto fail;
923
924         return q;
925
926 fail:
927         if (q)
928                 asyncns_cancel(asyncns, q);
929
930         return NULL;
931 }
932
933 int asyncns_getnameinfo_done(asyncns_t *asyncns, asyncns_query_t* q, char *ret_host, size_t hostlen, char *ret_serv, size_t servlen) {
934         int ret;
935         assert(asyncns);
936         assert(q);
937         assert(q->asyncns == asyncns);
938         assert(q->type == REQUEST_NAMEINFO);
939         assert(!ret_host || hostlen);
940         assert(!ret_serv || servlen);
941
942         if (asyncns->dead) {
943                 errno = ECHILD;
944                 return EAI_SYSTEM;
945         }
946
947         if (!q->done)
948                 return EAI_AGAIN;
949
950         if (ret_host && q->host) {
951                 strncpy(ret_host, q->host, hostlen);
952                 ret_host[hostlen-1] = 0;
953         }
954
955         if (ret_serv && q->serv) {
956                 strncpy(ret_serv, q->serv, servlen);
957                 ret_serv[servlen-1] = 0;
958         }
959
960         ret = q->ret;
961
962         if (ret == EAI_SYSTEM)
963                 errno = q->_errno;
964
965         if (ret != 0)
966                 h_errno = q->_h_errno;
967
968         asyncns_cancel(asyncns, q);
969
970         return ret;
971 }
972
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;
976         asyncns_query_t *q;
977
978         assert(asyncns);
979         assert(dname);
980
981         if (asyncns->dead) {
982                 errno = ECHILD;
983                 return NULL;
984         }
985
986         if (!(q = alloc_query(asyncns)))
987                 return NULL;
988
989         req->dname_len = strlen(dname) + 1;
990
991         req->header.id = q->id;
992         req->header.type = q->type = qtype;
993         req->header.length = sizeof(res_request_t) + req->dname_len;
994
995         if (req->header.length > BUFSIZE) {
996                 errno = ENOMEM;
997                 goto fail;
998         }
999
1000         req->class = class;
1001         req->type = type;
1002
1003         strcpy((char*) req + sizeof(res_request_t), dname);
1004
1005         if (send(asyncns->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0)
1006                 goto fail;
1007
1008         return q;
1009
1010 fail:
1011         if (q)
1012                 asyncns_cancel(asyncns, q);
1013
1014         return NULL;
1015 }
1016
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);
1019 }
1020
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);
1023 }
1024
1025 int asyncns_res_done(asyncns_t *asyncns, asyncns_query_t* q, unsigned char **answer) {
1026         int ret;
1027         assert(asyncns);
1028         assert(q);
1029         assert(q->asyncns == asyncns);
1030         assert(q->type == REQUEST_RES_QUERY || q->type == REQUEST_RES_SEARCH);
1031         assert(answer);
1032
1033         if (asyncns->dead) {
1034                 errno = ECHILD;
1035                 return -ECHILD;
1036         }
1037
1038         if (!q->done) {
1039                 errno = EAGAIN;
1040                 return -EAGAIN;
1041         }
1042
1043         *answer = (unsigned char *)q->serv;
1044         q->serv = NULL;
1045
1046         ret = q->ret;
1047
1048         if (ret < 0) {
1049                 errno = q->_errno;
1050                 h_errno = q->_h_errno;
1051         }
1052
1053         asyncns_cancel(asyncns, q);
1054
1055         return ret < 0 ? -errno : ret;
1056 }
1057
1058 asyncns_query_t* asyncns_getnext(asyncns_t *asyncns) {
1059         assert(asyncns);
1060         return asyncns->done_head;
1061 }
1062
1063 int asyncns_getnqueries(asyncns_t *asyncns) {
1064         assert(asyncns);
1065         return asyncns->n_queries;
1066 }
1067
1068 void asyncns_cancel(asyncns_t *asyncns, asyncns_query_t* q) {
1069         int i;
1070         int saved_errno = errno;
1071
1072         assert(asyncns);
1073         assert(q);
1074         assert(q->asyncns == asyncns);
1075         assert(asyncns->n_queries > 0);
1076
1077         if (q->done) {
1078
1079                 if (q->done_prev)
1080                         q->done_prev->done_next = q->done_next;
1081                 else
1082                         asyncns->done_head = q->done_next;
1083
1084                 if (q->done_next)
1085                         q->done_next->done_prev = q->done_prev;
1086                 else
1087                         asyncns->done_tail = q->done_prev;
1088         }
1089
1090         i = q->id % MAX_QUERIES;
1091         assert(asyncns->queries[i] == q);
1092         asyncns->queries[i] = NULL;
1093
1094         asyncns_freeaddrinfo(q->addrinfo);
1095         free(q->host);
1096         free(q->serv);
1097
1098         asyncns->n_queries--;
1099         free(q);
1100
1101         errno = saved_errno;
1102 }
1103
1104 void asyncns_freeaddrinfo(struct addrinfo *ai) {
1105         int saved_errno = errno;
1106
1107         while (ai) {
1108                 struct addrinfo *next = ai->ai_next;
1109
1110                 free(ai->ai_addr);
1111                 free(ai->ai_canonname);
1112                 free(ai);
1113
1114                 ai = next;
1115         }
1116
1117         errno = saved_errno;
1118 }
1119
1120 void asyncns_freeanswer(unsigned char *answer) {
1121         int saved_errno = errno;
1122
1123         if (!answer)
1124                 return;
1125
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! */
1130
1131         free(answer);
1132
1133         errno = saved_errno;
1134 }
1135
1136 int asyncns_isdone(asyncns_t *asyncns, asyncns_query_t*q) {
1137         assert(asyncns);
1138         assert(q);
1139         assert(q->asyncns == asyncns);
1140
1141         return q->done;
1142 }
1143
1144 void asyncns_setuserdata(asyncns_t *asyncns, asyncns_query_t *q, void *userdata) {
1145         assert(q);
1146         assert(asyncns);
1147         assert(q->asyncns = asyncns);
1148
1149         q->userdata = userdata;
1150 }
1151
1152 void* asyncns_getuserdata(asyncns_t *asyncns, asyncns_query_t *q) {
1153         assert(q);
1154         assert(asyncns);
1155         assert(q->asyncns = asyncns);
1156
1157         return q->userdata;
1158 }