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