Line data Source code
1 : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2 :
3 : /***
4 : This file is part of systemd.
5 :
6 : Copyright 2005-2008 Lennart Poettering
7 :
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.
12 :
13 : systemd is distributed in the hope that it will be useful, but
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 :
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 : ***/
21 :
22 : #include <signal.h>
23 : #include <unistd.h>
24 : #include <stdio.h>
25 : #include <string.h>
26 : #include <stdlib.h>
27 : #include <errno.h>
28 : #include <resolv.h>
29 : #include <stdint.h>
30 : #include <pthread.h>
31 : #include <sys/prctl.h>
32 : #include <poll.h>
33 :
34 : #include "util.h"
35 : #include "list.h"
36 : #include "socket-util.h"
37 : #include "missing.h"
38 : #include "resolve-util.h"
39 : #include "sd-resolve.h"
40 :
41 : #define WORKERS_MIN 1U
42 : #define WORKERS_MAX 16U
43 : #define QUERIES_MAX 256U
44 : #define BUFSIZE 10240U
45 :
46 : typedef enum {
47 : REQUEST_ADDRINFO,
48 : RESPONSE_ADDRINFO,
49 : REQUEST_NAMEINFO,
50 : RESPONSE_NAMEINFO,
51 : REQUEST_RES_QUERY,
52 : REQUEST_RES_SEARCH,
53 : RESPONSE_RES,
54 : REQUEST_TERMINATE,
55 : RESPONSE_DIED
56 : } QueryType;
57 :
58 : enum {
59 : REQUEST_RECV_FD,
60 : REQUEST_SEND_FD,
61 : RESPONSE_RECV_FD,
62 : RESPONSE_SEND_FD,
63 : _FD_MAX
64 : };
65 :
66 : struct sd_resolve {
67 : unsigned n_ref;
68 :
69 : bool dead:1;
70 : pid_t original_pid;
71 :
72 : int fds[_FD_MAX];
73 :
74 : pthread_t workers[WORKERS_MAX];
75 : unsigned n_valid_workers;
76 :
77 : unsigned current_id;
78 : sd_resolve_query* query_array[QUERIES_MAX];
79 : unsigned n_queries, n_done, n_outstanding;
80 :
81 : sd_event_source *event_source;
82 : sd_event *event;
83 :
84 : sd_resolve_query *current;
85 :
86 : sd_resolve **default_resolve_ptr;
87 : pid_t tid;
88 :
89 : LIST_HEAD(sd_resolve_query, queries);
90 : };
91 :
92 : struct sd_resolve_query {
93 : unsigned n_ref;
94 :
95 : sd_resolve *resolve;
96 :
97 : QueryType type:4;
98 : bool done:1;
99 : bool floating:1;
100 : unsigned id;
101 :
102 : int ret;
103 : int _errno;
104 : int _h_errno;
105 : struct addrinfo *addrinfo;
106 : char *serv, *host;
107 : unsigned char *answer;
108 :
109 : union {
110 : sd_resolve_getaddrinfo_handler_t getaddrinfo_handler;
111 : sd_resolve_getnameinfo_handler_t getnameinfo_handler;
112 : sd_resolve_res_handler_t res_handler;
113 : };
114 :
115 : void *userdata;
116 :
117 : LIST_FIELDS(sd_resolve_query, queries);
118 : };
119 :
120 : typedef struct RHeader {
121 : QueryType type;
122 : unsigned id;
123 : size_t length;
124 : } RHeader;
125 :
126 : typedef struct AddrInfoRequest {
127 : struct RHeader header;
128 : bool hints_valid;
129 : int ai_flags;
130 : int ai_family;
131 : int ai_socktype;
132 : int ai_protocol;
133 : size_t node_len, service_len;
134 : } AddrInfoRequest;
135 :
136 : typedef struct AddrInfoResponse {
137 : struct RHeader header;
138 : int ret;
139 : int _errno;
140 : int _h_errno;
141 : /* followed by addrinfo_serialization[] */
142 : } AddrInfoResponse;
143 :
144 : typedef struct AddrInfoSerialization {
145 : int ai_flags;
146 : int ai_family;
147 : int ai_socktype;
148 : int ai_protocol;
149 : size_t ai_addrlen;
150 : size_t canonname_len;
151 : /* Followed by ai_addr amd ai_canonname with variable lengths */
152 : } AddrInfoSerialization;
153 :
154 : typedef struct NameInfoRequest {
155 : struct RHeader header;
156 : int flags;
157 : socklen_t sockaddr_len;
158 : bool gethost:1, getserv:1;
159 : } NameInfoRequest;
160 :
161 : typedef struct NameInfoResponse {
162 : struct RHeader header;
163 : size_t hostlen, servlen;
164 : int ret;
165 : int _errno;
166 : int _h_errno;
167 : } NameInfoResponse;
168 :
169 : typedef struct ResRequest {
170 : struct RHeader header;
171 : int class;
172 : int type;
173 : size_t dname_len;
174 : } ResRequest;
175 :
176 : typedef struct ResResponse {
177 : struct RHeader header;
178 : int ret;
179 : int _errno;
180 : int _h_errno;
181 : } ResResponse;
182 :
183 : typedef union Packet {
184 : RHeader rheader;
185 : AddrInfoRequest addrinfo_request;
186 : AddrInfoResponse addrinfo_response;
187 : NameInfoRequest nameinfo_request;
188 : NameInfoResponse nameinfo_response;
189 : ResRequest res_request;
190 : ResResponse res_response;
191 : } Packet;
192 :
193 : static int getaddrinfo_done(sd_resolve_query* q);
194 : static int getnameinfo_done(sd_resolve_query *q);
195 : static int res_query_done(sd_resolve_query* q);
196 :
197 : static void resolve_query_disconnect(sd_resolve_query *q);
198 :
199 : #define RESOLVE_DONT_DESTROY(resolve) \
200 : _cleanup_resolve_unref_ _unused_ sd_resolve *_dont_destroy_##resolve = sd_resolve_ref(resolve)
201 :
202 4 : static int send_died(int out_fd) {
203 :
204 4 : RHeader rh = {
205 : .type = RESPONSE_DIED,
206 : .length = sizeof(RHeader),
207 : };
208 :
209 4 : assert(out_fd >= 0);
210 :
211 4 : if (send(out_fd, &rh, rh.length, MSG_NOSIGNAL) < 0)
212 0 : return -errno;
213 :
214 4 : return 0;
215 : }
216 :
217 6 : static void *serialize_addrinfo(void *p, const struct addrinfo *ai, size_t *length, size_t maxlength) {
218 : AddrInfoSerialization s;
219 : size_t cnl, l;
220 :
221 6 : assert(p);
222 6 : assert(ai);
223 6 : assert(length);
224 6 : assert(*length <= maxlength);
225 :
226 6 : cnl = ai->ai_canonname ? strlen(ai->ai_canonname)+1 : 0;
227 6 : l = sizeof(AddrInfoSerialization) + ai->ai_addrlen + cnl;
228 :
229 6 : if (*length + l > maxlength)
230 0 : return NULL;
231 :
232 6 : s.ai_flags = ai->ai_flags;
233 6 : s.ai_family = ai->ai_family;
234 6 : s.ai_socktype = ai->ai_socktype;
235 6 : s.ai_protocol = ai->ai_protocol;
236 6 : s.ai_addrlen = ai->ai_addrlen;
237 6 : s.canonname_len = cnl;
238 :
239 6 : memcpy((uint8_t*) p, &s, sizeof(AddrInfoSerialization));
240 6 : memcpy((uint8_t*) p + sizeof(AddrInfoSerialization), ai->ai_addr, ai->ai_addrlen);
241 :
242 6 : if (ai->ai_canonname)
243 1 : memcpy((char*) p + sizeof(AddrInfoSerialization) + ai->ai_addrlen, ai->ai_canonname, cnl);
244 :
245 6 : *length += l;
246 6 : return (uint8_t*) p + l;
247 : }
248 :
249 2 : static int send_addrinfo_reply(
250 : int out_fd,
251 : unsigned id,
252 : int ret,
253 : struct addrinfo *ai,
254 : int _errno,
255 : int _h_errno) {
256 :
257 2 : AddrInfoResponse resp = {
258 : .header.type = RESPONSE_ADDRINFO,
259 : .header.id = id,
260 : .header.length = sizeof(AddrInfoResponse),
261 : .ret = ret,
262 : ._errno = _errno,
263 : ._h_errno = _h_errno,
264 : };
265 :
266 2 : struct msghdr mh = {};
267 : struct iovec iov[2];
268 : union {
269 : AddrInfoSerialization ais;
270 : uint8_t space[BUFSIZE];
271 : } buffer;
272 :
273 2 : assert(out_fd >= 0);
274 :
275 2 : if (ret == 0 && ai) {
276 2 : void *p = &buffer;
277 : struct addrinfo *k;
278 :
279 8 : for (k = ai; k; k = k->ai_next) {
280 6 : p = serialize_addrinfo(p, k, &resp.header.length, (uint8_t*) &buffer + BUFSIZE - (uint8_t*) p);
281 6 : if (!p) {
282 0 : freeaddrinfo(ai);
283 0 : return -ENOBUFS;
284 : }
285 : }
286 : }
287 :
288 2 : if (ai)
289 2 : freeaddrinfo(ai);
290 :
291 2 : iov[0] = (struct iovec) { .iov_base = &resp, .iov_len = sizeof(AddrInfoResponse) };
292 2 : iov[1] = (struct iovec) { .iov_base = &buffer, .iov_len = resp.header.length - sizeof(AddrInfoResponse) };
293 :
294 2 : mh.msg_iov = iov;
295 2 : mh.msg_iovlen = ELEMENTSOF(iov);
296 :
297 2 : if (sendmsg(out_fd, &mh, MSG_NOSIGNAL) < 0)
298 0 : return -errno;
299 :
300 2 : return 0;
301 : }
302 :
303 1 : static int send_nameinfo_reply(
304 : int out_fd,
305 : unsigned id,
306 : int ret,
307 : const char *host,
308 : const char *serv,
309 : int _errno,
310 : int _h_errno) {
311 :
312 1 : NameInfoResponse resp = {
313 : .header.type = RESPONSE_NAMEINFO,
314 : .header.id = id,
315 : .ret = ret,
316 : ._errno = _errno,
317 : ._h_errno = _h_errno,
318 : };
319 :
320 1 : struct msghdr mh = {};
321 : struct iovec iov[3];
322 : size_t hl, sl;
323 :
324 1 : assert(out_fd >= 0);
325 :
326 1 : sl = serv ? strlen(serv)+1 : 0;
327 1 : hl = host ? strlen(host)+1 : 0;
328 :
329 1 : resp.header.length = sizeof(NameInfoResponse) + hl + sl;
330 1 : resp.hostlen = hl;
331 1 : resp.servlen = sl;
332 :
333 1 : iov[0] = (struct iovec) { .iov_base = &resp, .iov_len = sizeof(NameInfoResponse) };
334 1 : iov[1] = (struct iovec) { .iov_base = (void*) host, .iov_len = hl };
335 1 : iov[2] = (struct iovec) { .iov_base = (void*) serv, .iov_len = sl };
336 :
337 1 : mh.msg_iov = iov;
338 1 : mh.msg_iovlen = ELEMENTSOF(iov);
339 :
340 1 : if (sendmsg(out_fd, &mh, MSG_NOSIGNAL) < 0)
341 0 : return -errno;
342 :
343 1 : return 0;
344 : }
345 :
346 1 : static int send_res_reply(int out_fd, unsigned id, const unsigned char *answer, int ret, int _errno, int _h_errno) {
347 :
348 1 : ResResponse resp = {
349 : .header.type = RESPONSE_RES,
350 : .header.id = id,
351 : .ret = ret,
352 : ._errno = _errno,
353 : ._h_errno = _h_errno,
354 : };
355 :
356 1 : struct msghdr mh = {};
357 : struct iovec iov[2];
358 : size_t l;
359 :
360 1 : assert(out_fd >= 0);
361 :
362 1 : l = ret > 0 ? (size_t) ret : 0;
363 :
364 1 : resp.header.length = sizeof(ResResponse) + l;
365 :
366 1 : iov[0] = (struct iovec) { .iov_base = &resp, .iov_len = sizeof(ResResponse) };
367 1 : iov[1] = (struct iovec) { .iov_base = (void*) answer, .iov_len = l };
368 :
369 1 : mh.msg_iov = iov;
370 1 : mh.msg_iovlen = ELEMENTSOF(iov);
371 :
372 1 : if (sendmsg(out_fd, &mh, MSG_NOSIGNAL) < 0)
373 0 : return -errno;
374 :
375 1 : return 0;
376 : }
377 :
378 4 : static int handle_request(int out_fd, const Packet *packet, size_t length) {
379 : const RHeader *req;
380 :
381 4 : assert(out_fd >= 0);
382 4 : assert(packet);
383 :
384 4 : req = &packet->rheader;
385 :
386 4 : assert(length >= sizeof(RHeader));
387 4 : assert(length == req->length);
388 :
389 4 : switch (req->type) {
390 :
391 : case REQUEST_ADDRINFO: {
392 2 : const AddrInfoRequest *ai_req = &packet->addrinfo_request;
393 2 : struct addrinfo hints = {}, *result = NULL;
394 : const char *node, *service;
395 : int ret;
396 :
397 2 : assert(length >= sizeof(AddrInfoRequest));
398 2 : assert(length == sizeof(AddrInfoRequest) + ai_req->node_len + ai_req->service_len);
399 :
400 2 : hints.ai_flags = ai_req->ai_flags;
401 2 : hints.ai_family = ai_req->ai_family;
402 2 : hints.ai_socktype = ai_req->ai_socktype;
403 2 : hints.ai_protocol = ai_req->ai_protocol;
404 :
405 2 : node = ai_req->node_len ? (const char*) ai_req + sizeof(AddrInfoRequest) : NULL;
406 2 : service = ai_req->service_len ? (const char*) ai_req + sizeof(AddrInfoRequest) + ai_req->node_len : NULL;
407 :
408 2 : ret = getaddrinfo(
409 : node, service,
410 2 : ai_req->hints_valid ? &hints : NULL,
411 : &result);
412 :
413 : /* send_addrinfo_reply() frees result */
414 2 : return send_addrinfo_reply(out_fd, req->id, ret, result, errno, h_errno);
415 : }
416 :
417 : case REQUEST_NAMEINFO: {
418 1 : const NameInfoRequest *ni_req = &packet->nameinfo_request;
419 : char hostbuf[NI_MAXHOST], servbuf[NI_MAXSERV];
420 : union sockaddr_union sa;
421 : int ret;
422 :
423 1 : assert(length >= sizeof(NameInfoRequest));
424 1 : assert(length == sizeof(NameInfoRequest) + ni_req->sockaddr_len);
425 1 : assert(sizeof(sa) >= ni_req->sockaddr_len);
426 :
427 1 : memcpy(&sa, (const uint8_t *) ni_req + sizeof(NameInfoRequest), ni_req->sockaddr_len);
428 :
429 5 : ret = getnameinfo(&sa.sa, ni_req->sockaddr_len,
430 2 : ni_req->gethost ? hostbuf : NULL, ni_req->gethost ? sizeof(hostbuf) : 0,
431 2 : ni_req->getserv ? servbuf : NULL, ni_req->getserv ? sizeof(servbuf) : 0,
432 : ni_req->flags);
433 :
434 4 : return send_nameinfo_reply(out_fd, req->id, ret,
435 1 : ret == 0 && ni_req->gethost ? hostbuf : NULL,
436 1 : ret == 0 && ni_req->getserv ? servbuf : NULL,
437 2 : errno, h_errno);
438 : }
439 :
440 : case REQUEST_RES_QUERY:
441 : case REQUEST_RES_SEARCH: {
442 1 : const ResRequest *res_req = &packet->res_request;
443 : union {
444 : HEADER header;
445 : uint8_t space[BUFSIZE];
446 : } answer;
447 : const char *dname;
448 : int ret;
449 :
450 1 : assert(length >= sizeof(ResRequest));
451 1 : assert(length == sizeof(ResRequest) + res_req->dname_len);
452 :
453 1 : dname = (const char *) res_req + sizeof(ResRequest);
454 :
455 1 : if (req->type == REQUEST_RES_QUERY)
456 1 : ret = res_query(dname, res_req->class, res_req->type, (unsigned char *) &answer, BUFSIZE);
457 : else
458 0 : ret = res_search(dname, res_req->class, res_req->type, (unsigned char *) &answer, BUFSIZE);
459 :
460 1 : return send_res_reply(out_fd, req->id, (unsigned char *) &answer, ret, errno, h_errno);
461 : }
462 :
463 : case REQUEST_TERMINATE:
464 : /* Quit */
465 0 : return -ECONNRESET;
466 :
467 : default:
468 0 : assert_not_reached("Unknown request");
469 : }
470 :
471 : return 0;
472 : }
473 :
474 4 : static void* thread_worker(void *p) {
475 4 : sd_resolve *resolve = p;
476 : sigset_t fullset;
477 :
478 : /* No signals in this thread please */
479 4 : assert_se(sigfillset(&fullset) == 0);
480 3 : assert_se(pthread_sigmask(SIG_BLOCK, &fullset, NULL) == 0);
481 :
482 : /* Assign a pretty name to this thread */
483 4 : prctl(PR_SET_NAME, (unsigned long) "sd-resolve");
484 :
485 4 : while (!resolve->dead) {
486 : union {
487 : Packet packet;
488 : uint8_t space[BUFSIZE];
489 : } buf;
490 : ssize_t length;
491 :
492 7 : length = recv(resolve->fds[REQUEST_RECV_FD], &buf, sizeof(buf), 0);
493 7 : if (length < 0) {
494 0 : if (errno == EINTR)
495 0 : continue;
496 :
497 3 : break;
498 : }
499 7 : if (length == 0)
500 0 : break;
501 :
502 7 : if (resolve->dead)
503 3 : break;
504 :
505 4 : if (handle_request(resolve->fds[RESPONSE_SEND_FD], &buf.packet, (size_t) length) < 0)
506 0 : break;
507 : }
508 :
509 4 : send_died(resolve->fds[RESPONSE_SEND_FD]);
510 :
511 4 : return NULL;
512 : }
513 :
514 4 : static int start_threads(sd_resolve *resolve, unsigned extra) {
515 : unsigned n;
516 : int r;
517 :
518 4 : n = resolve->n_outstanding + extra;
519 4 : n = CLAMP(n, WORKERS_MIN, WORKERS_MAX);
520 :
521 12 : while (resolve->n_valid_workers < n) {
522 :
523 4 : r = pthread_create(&resolve->workers[resolve->n_valid_workers], NULL, thread_worker, resolve);
524 4 : if (r != 0)
525 0 : return -r;
526 :
527 4 : resolve->n_valid_workers ++;
528 : }
529 :
530 4 : return 0;
531 : }
532 :
533 16 : static bool resolve_pid_changed(sd_resolve *r) {
534 16 : assert(r);
535 :
536 : /* We don't support people creating a resolver and keeping it
537 : * around after fork(). Let's complain. */
538 :
539 16 : return r->original_pid != getpid();
540 : }
541 :
542 1 : _public_ int sd_resolve_new(sd_resolve **ret) {
543 1 : sd_resolve *resolve = NULL;
544 : int i, r;
545 :
546 1 : assert_return(ret, -EINVAL);
547 :
548 1 : resolve = new0(sd_resolve, 1);
549 1 : if (!resolve)
550 0 : return -ENOMEM;
551 :
552 1 : resolve->n_ref = 1;
553 1 : resolve->original_pid = getpid();
554 :
555 5 : for (i = 0; i < _FD_MAX; i++)
556 4 : resolve->fds[i] = -1;
557 :
558 1 : r = socketpair(PF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, resolve->fds + REQUEST_RECV_FD);
559 1 : if (r < 0) {
560 0 : r = -errno;
561 0 : goto fail;
562 : }
563 :
564 1 : r = socketpair(PF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, resolve->fds + RESPONSE_RECV_FD);
565 1 : if (r < 0) {
566 0 : r = -errno;
567 0 : goto fail;
568 : }
569 :
570 1 : fd_inc_sndbuf(resolve->fds[REQUEST_SEND_FD], QUERIES_MAX * BUFSIZE);
571 1 : fd_inc_rcvbuf(resolve->fds[REQUEST_RECV_FD], QUERIES_MAX * BUFSIZE);
572 1 : fd_inc_sndbuf(resolve->fds[RESPONSE_SEND_FD], QUERIES_MAX * BUFSIZE);
573 1 : fd_inc_rcvbuf(resolve->fds[RESPONSE_RECV_FD], QUERIES_MAX * BUFSIZE);
574 :
575 1 : fd_nonblock(resolve->fds[RESPONSE_RECV_FD], true);
576 :
577 1 : *ret = resolve;
578 1 : return 0;
579 :
580 : fail:
581 0 : sd_resolve_unref(resolve);
582 0 : return r;
583 : }
584 :
585 1 : _public_ int sd_resolve_default(sd_resolve **ret) {
586 :
587 : static thread_local sd_resolve *default_resolve = NULL;
588 1 : sd_resolve *e = NULL;
589 : int r;
590 :
591 1 : if (!ret)
592 0 : return !!default_resolve;
593 :
594 1 : if (default_resolve) {
595 0 : *ret = sd_resolve_ref(default_resolve);
596 0 : return 0;
597 : }
598 :
599 1 : r = sd_resolve_new(&e);
600 1 : if (r < 0)
601 0 : return r;
602 :
603 1 : e->default_resolve_ptr = &default_resolve;
604 1 : e->tid = gettid();
605 1 : default_resolve = e;
606 :
607 1 : *ret = e;
608 1 : return 1;
609 : }
610 :
611 0 : _public_ int sd_resolve_get_tid(sd_resolve *resolve, pid_t *tid) {
612 0 : assert_return(resolve, -EINVAL);
613 0 : assert_return(tid, -EINVAL);
614 0 : assert_return(!resolve_pid_changed(resolve), -ECHILD);
615 :
616 0 : if (resolve->tid != 0) {
617 0 : *tid = resolve->tid;
618 0 : return 0;
619 : }
620 :
621 0 : if (resolve->event)
622 0 : return sd_event_get_tid(resolve->event, tid);
623 :
624 0 : return -ENXIO;
625 : }
626 :
627 1 : static void resolve_free(sd_resolve *resolve) {
628 2 : PROTECT_ERRNO;
629 : sd_resolve_query *q;
630 : unsigned i;
631 :
632 1 : assert(resolve);
633 :
634 3 : while ((q = resolve->queries)) {
635 1 : assert(q->floating);
636 1 : resolve_query_disconnect(q);
637 1 : sd_resolve_query_unref(q);
638 : }
639 :
640 1 : if (resolve->default_resolve_ptr)
641 1 : *(resolve->default_resolve_ptr) = NULL;
642 :
643 1 : resolve->dead = true;
644 :
645 1 : sd_resolve_detach_event(resolve);
646 :
647 1 : if (resolve->fds[REQUEST_SEND_FD] >= 0) {
648 :
649 1 : RHeader req = {
650 : .type = REQUEST_TERMINATE,
651 : .length = sizeof(req)
652 : };
653 :
654 : /* Send one termination packet for each worker */
655 5 : for (i = 0; i < resolve->n_valid_workers; i++)
656 4 : (void) send(resolve->fds[REQUEST_SEND_FD], &req, req.length, MSG_NOSIGNAL);
657 : }
658 :
659 : /* Now terminate them and wait until they are gone. */
660 5 : for (i = 0; i < resolve->n_valid_workers; i++) {
661 : for (;;) {
662 4 : if (pthread_join(resolve->workers[i], NULL) != EINTR)
663 4 : break;
664 0 : }
665 : }
666 :
667 : /* Close all communication channels */
668 5 : for (i = 0; i < _FD_MAX; i++)
669 4 : safe_close(resolve->fds[i]);
670 :
671 1 : free(resolve);
672 1 : }
673 :
674 6 : _public_ sd_resolve* sd_resolve_ref(sd_resolve *resolve) {
675 6 : assert_return(resolve, NULL);
676 :
677 6 : assert(resolve->n_ref >= 1);
678 6 : resolve->n_ref++;
679 :
680 6 : return resolve;
681 : }
682 :
683 7 : _public_ sd_resolve* sd_resolve_unref(sd_resolve *resolve) {
684 :
685 7 : if (!resolve)
686 0 : return NULL;
687 :
688 7 : assert(resolve->n_ref >= 1);
689 7 : resolve->n_ref--;
690 :
691 7 : if (resolve->n_ref <= 0)
692 1 : resolve_free(resolve);
693 :
694 7 : return NULL;
695 : }
696 :
697 0 : _public_ int sd_resolve_get_fd(sd_resolve *resolve) {
698 0 : assert_return(resolve, -EINVAL);
699 0 : assert_return(!resolve_pid_changed(resolve), -ECHILD);
700 :
701 0 : return resolve->fds[RESPONSE_RECV_FD];
702 : }
703 :
704 0 : _public_ int sd_resolve_get_events(sd_resolve *resolve) {
705 0 : assert_return(resolve, -EINVAL);
706 0 : assert_return(!resolve_pid_changed(resolve), -ECHILD);
707 :
708 0 : return resolve->n_queries > resolve->n_done ? POLLIN : 0;
709 : }
710 :
711 0 : _public_ int sd_resolve_get_timeout(sd_resolve *resolve, uint64_t *usec) {
712 0 : assert_return(resolve, -EINVAL);
713 0 : assert_return(usec, -EINVAL);
714 0 : assert_return(!resolve_pid_changed(resolve), -ECHILD);
715 :
716 0 : *usec = (uint64_t) -1;
717 0 : return 0;
718 : }
719 :
720 3 : static sd_resolve_query *lookup_query(sd_resolve *resolve, unsigned id) {
721 : sd_resolve_query *q;
722 :
723 3 : assert(resolve);
724 :
725 3 : q = resolve->query_array[id % QUERIES_MAX];
726 3 : if (q)
727 3 : if (q->id == id)
728 3 : return q;
729 :
730 0 : return NULL;
731 : }
732 :
733 3 : static int complete_query(sd_resolve *resolve, sd_resolve_query *q) {
734 : int r;
735 :
736 3 : assert(q);
737 3 : assert(!q->done);
738 3 : assert(q->resolve == resolve);
739 :
740 3 : q->done = true;
741 3 : resolve->n_done ++;
742 :
743 3 : resolve->current = sd_resolve_query_ref(q);
744 :
745 3 : switch (q->type) {
746 :
747 : case REQUEST_ADDRINFO:
748 1 : r = getaddrinfo_done(q);
749 1 : break;
750 :
751 : case REQUEST_NAMEINFO:
752 1 : r = getnameinfo_done(q);
753 1 : break;
754 :
755 : case REQUEST_RES_QUERY:
756 : case REQUEST_RES_SEARCH:
757 1 : r = res_query_done(q);
758 1 : break;
759 :
760 : default:
761 0 : assert_not_reached("Cannot complete unknown query type");
762 : }
763 :
764 3 : resolve->current = NULL;
765 :
766 3 : if (q->floating) {
767 0 : resolve_query_disconnect(q);
768 0 : sd_resolve_query_unref(q);
769 : }
770 :
771 3 : sd_resolve_query_unref(q);
772 :
773 3 : return r;
774 : }
775 :
776 2 : static int unserialize_addrinfo(const void **p, size_t *length, struct addrinfo **ret_ai) {
777 : AddrInfoSerialization s;
778 : size_t l;
779 : struct addrinfo *ai;
780 :
781 2 : assert(p);
782 2 : assert(*p);
783 2 : assert(ret_ai);
784 2 : assert(length);
785 :
786 2 : if (*length < sizeof(AddrInfoSerialization))
787 0 : return -EBADMSG;
788 :
789 2 : memcpy(&s, *p, sizeof(s));
790 :
791 2 : l = sizeof(AddrInfoSerialization) + s.ai_addrlen + s.canonname_len;
792 2 : if (*length < l)
793 0 : return -EBADMSG;
794 :
795 2 : ai = new0(struct addrinfo, 1);
796 2 : if (!ai)
797 0 : return -ENOMEM;
798 :
799 2 : ai->ai_flags = s.ai_flags;
800 2 : ai->ai_family = s.ai_family;
801 2 : ai->ai_socktype = s.ai_socktype;
802 2 : ai->ai_protocol = s.ai_protocol;
803 2 : ai->ai_addrlen = s.ai_addrlen;
804 :
805 2 : if (s.ai_addrlen > 0) {
806 2 : ai->ai_addr = memdup((const uint8_t*) *p + sizeof(AddrInfoSerialization), s.ai_addrlen);
807 2 : if (!ai->ai_addr) {
808 0 : free(ai);
809 0 : return -ENOMEM;
810 : }
811 : }
812 :
813 2 : if (s.canonname_len > 0) {
814 1 : ai->ai_canonname = memdup((const uint8_t*) *p + sizeof(AddrInfoSerialization) + s.ai_addrlen, s.canonname_len);
815 1 : if (!ai->ai_canonname) {
816 0 : free(ai->ai_addr);
817 0 : free(ai);
818 0 : return -ENOMEM;
819 : }
820 : }
821 :
822 2 : *length -= l;
823 2 : *ret_ai = ai;
824 2 : *p = ((const uint8_t*) *p) + l;
825 :
826 2 : return 0;
827 : }
828 :
829 3 : static int handle_response(sd_resolve *resolve, const Packet *packet, size_t length) {
830 : const RHeader *resp;
831 : sd_resolve_query *q;
832 : int r;
833 :
834 3 : assert(resolve);
835 :
836 3 : resp = &packet->rheader;
837 3 : assert(resp);
838 3 : assert(length >= sizeof(RHeader));
839 3 : assert(length == resp->length);
840 :
841 3 : if (resp->type == RESPONSE_DIED) {
842 0 : resolve->dead = true;
843 0 : return 0;
844 : }
845 :
846 3 : assert(resolve->n_outstanding > 0);
847 3 : resolve->n_outstanding--;
848 :
849 3 : q = lookup_query(resolve, resp->id);
850 3 : if (!q)
851 0 : return 0;
852 :
853 3 : switch (resp->type) {
854 :
855 : case RESPONSE_ADDRINFO: {
856 1 : const AddrInfoResponse *ai_resp = &packet->addrinfo_response;
857 : const void *p;
858 : size_t l;
859 1 : struct addrinfo *prev = NULL;
860 :
861 1 : assert(length >= sizeof(AddrInfoResponse));
862 1 : assert(q->type == REQUEST_ADDRINFO);
863 :
864 1 : q->ret = ai_resp->ret;
865 1 : q->_errno = ai_resp->_errno;
866 1 : q->_h_errno = ai_resp->_h_errno;
867 :
868 1 : l = length - sizeof(AddrInfoResponse);
869 1 : p = (const uint8_t*) resp + sizeof(AddrInfoResponse);
870 :
871 4 : while (l > 0 && p) {
872 2 : struct addrinfo *ai = NULL;
873 :
874 2 : r = unserialize_addrinfo(&p, &l, &ai);
875 2 : if (r < 0) {
876 0 : q->ret = EAI_SYSTEM;
877 0 : q->_errno = -r;
878 0 : q->_h_errno = 0;
879 0 : freeaddrinfo(q->addrinfo);
880 0 : q->addrinfo = NULL;
881 0 : break;
882 : }
883 :
884 2 : if (prev)
885 1 : prev->ai_next = ai;
886 : else
887 1 : q->addrinfo = ai;
888 :
889 2 : prev = ai;
890 : }
891 :
892 1 : return complete_query(resolve, q);
893 : }
894 :
895 : case RESPONSE_NAMEINFO: {
896 1 : const NameInfoResponse *ni_resp = &packet->nameinfo_response;
897 :
898 1 : assert(length >= sizeof(NameInfoResponse));
899 1 : assert(q->type == REQUEST_NAMEINFO);
900 :
901 1 : q->ret = ni_resp->ret;
902 1 : q->_errno = ni_resp->_errno;
903 1 : q->_h_errno = ni_resp->_h_errno;
904 :
905 1 : if (ni_resp->hostlen > 0) {
906 1 : q->host = strndup((const char*) ni_resp + sizeof(NameInfoResponse), ni_resp->hostlen-1);
907 1 : if (!q->host) {
908 0 : q->ret = EAI_MEMORY;
909 0 : q->_errno = ENOMEM;
910 0 : q->_h_errno = 0;
911 : }
912 : }
913 :
914 1 : if (ni_resp->servlen > 0) {
915 1 : q->serv = strndup((const char*) ni_resp + sizeof(NameInfoResponse) + ni_resp->hostlen, ni_resp->servlen-1);
916 1 : if (!q->serv) {
917 0 : q->ret = EAI_MEMORY;
918 0 : q->_errno = ENOMEM;
919 0 : q->_h_errno = 0;
920 : }
921 : }
922 :
923 1 : return complete_query(resolve, q);
924 : }
925 :
926 : case RESPONSE_RES: {
927 1 : const ResResponse *res_resp = &packet->res_response;
928 :
929 1 : assert(length >= sizeof(ResResponse));
930 1 : assert(q->type == REQUEST_RES_QUERY || q->type == REQUEST_RES_SEARCH);
931 :
932 1 : q->ret = res_resp->ret;
933 1 : q->_errno = res_resp->_errno;
934 1 : q->_h_errno = res_resp->_h_errno;
935 :
936 1 : if (res_resp->ret >= 0) {
937 1 : q->answer = memdup((const char *)resp + sizeof(ResResponse), res_resp->ret);
938 1 : if (!q->answer) {
939 0 : q->ret = -1;
940 0 : q->_errno = ENOMEM;
941 0 : q->_h_errno = 0;
942 : }
943 : }
944 :
945 1 : return complete_query(resolve, q);
946 : }
947 :
948 : default:
949 0 : return 0;
950 : }
951 : }
952 :
953 3 : _public_ int sd_resolve_process(sd_resolve *resolve) {
954 6 : RESOLVE_DONT_DESTROY(resolve);
955 :
956 : union {
957 : Packet packet;
958 : uint8_t space[BUFSIZE];
959 : } buf;
960 : ssize_t l;
961 : int r;
962 :
963 3 : assert_return(resolve, -EINVAL);
964 3 : assert_return(!resolve_pid_changed(resolve), -ECHILD);
965 :
966 : /* We don't allow recursively invoking sd_resolve_process(). */
967 3 : assert_return(!resolve->current, -EBUSY);
968 :
969 3 : l = recv(resolve->fds[RESPONSE_RECV_FD], &buf, sizeof(buf), 0);
970 3 : if (l < 0) {
971 0 : if (errno == EAGAIN)
972 0 : return 0;
973 :
974 0 : return -errno;
975 : }
976 3 : if (l == 0)
977 0 : return -ECONNREFUSED;
978 :
979 3 : r = handle_response(resolve, &buf.packet, (size_t) l);
980 3 : if (r < 0)
981 0 : return r;
982 :
983 3 : return 1;
984 : }
985 :
986 3 : _public_ int sd_resolve_wait(sd_resolve *resolve, uint64_t timeout_usec) {
987 : int r;
988 :
989 3 : assert_return(resolve, -EINVAL);
990 3 : assert_return(!resolve_pid_changed(resolve), -ECHILD);
991 :
992 3 : if (resolve->n_done >= resolve->n_queries)
993 0 : return 0;
994 :
995 : do {
996 3 : r = fd_wait_for_event(resolve->fds[RESPONSE_RECV_FD], POLLIN, timeout_usec);
997 3 : } while (r == -EINTR);
998 :
999 3 : if (r < 0)
1000 0 : return r;
1001 :
1002 3 : return sd_resolve_process(resolve);
1003 : }
1004 :
1005 4 : static int alloc_query(sd_resolve *resolve, bool floating, sd_resolve_query **_q) {
1006 : sd_resolve_query *q;
1007 : int r;
1008 :
1009 4 : assert(resolve);
1010 4 : assert(_q);
1011 :
1012 4 : if (resolve->n_queries >= QUERIES_MAX)
1013 0 : return -ENOBUFS;
1014 :
1015 4 : r = start_threads(resolve, 1);
1016 4 : if (r < 0)
1017 0 : return r;
1018 :
1019 8 : while (resolve->query_array[resolve->current_id % QUERIES_MAX])
1020 0 : resolve->current_id++;
1021 :
1022 4 : q = resolve->query_array[resolve->current_id % QUERIES_MAX] = new0(sd_resolve_query, 1);
1023 4 : if (!q)
1024 0 : return -ENOMEM;
1025 :
1026 4 : q->n_ref = 1;
1027 4 : q->resolve = resolve;
1028 4 : q->floating = floating;
1029 4 : q->id = resolve->current_id++;
1030 :
1031 4 : if (!floating)
1032 3 : sd_resolve_ref(resolve);
1033 :
1034 4 : LIST_PREPEND(queries, resolve->queries, q);
1035 4 : resolve->n_queries++;
1036 :
1037 4 : *_q = q;
1038 4 : return 0;
1039 : }
1040 :
1041 2 : _public_ int sd_resolve_getaddrinfo(
1042 : sd_resolve *resolve,
1043 : sd_resolve_query **_q,
1044 : const char *node, const char *service,
1045 : const struct addrinfo *hints,
1046 : sd_resolve_getaddrinfo_handler_t callback, void *userdata) {
1047 :
1048 2 : AddrInfoRequest req = {};
1049 2 : struct msghdr mh = {};
1050 : struct iovec iov[3];
1051 : sd_resolve_query *q;
1052 : int r;
1053 :
1054 2 : assert_return(resolve, -EINVAL);
1055 2 : assert_return(node || service, -EINVAL);
1056 2 : assert_return(callback, -EINVAL);
1057 2 : assert_return(!resolve_pid_changed(resolve), -ECHILD);
1058 :
1059 2 : r = alloc_query(resolve, !_q, &q);
1060 2 : if (r < 0)
1061 0 : return r;
1062 :
1063 2 : q->type = REQUEST_ADDRINFO;
1064 2 : q->getaddrinfo_handler = callback;
1065 2 : q->userdata = userdata;
1066 :
1067 2 : req.node_len = node ? strlen(node)+1 : 0;
1068 2 : req.service_len = service ? strlen(service)+1 : 0;
1069 :
1070 2 : req.header.id = q->id;
1071 2 : req.header.type = REQUEST_ADDRINFO;
1072 2 : req.header.length = sizeof(AddrInfoRequest) + req.node_len + req.service_len;
1073 :
1074 2 : if (hints) {
1075 1 : req.hints_valid = true;
1076 1 : req.ai_flags = hints->ai_flags;
1077 1 : req.ai_family = hints->ai_family;
1078 1 : req.ai_socktype = hints->ai_socktype;
1079 1 : req.ai_protocol = hints->ai_protocol;
1080 : }
1081 :
1082 2 : iov[mh.msg_iovlen++] = (struct iovec) { .iov_base = &req, .iov_len = sizeof(AddrInfoRequest) };
1083 2 : if (node)
1084 2 : iov[mh.msg_iovlen++] = (struct iovec) { .iov_base = (void*) node, .iov_len = req.node_len };
1085 2 : if (service)
1086 1 : iov[mh.msg_iovlen++] = (struct iovec) { .iov_base = (void*) service, .iov_len = req.service_len };
1087 2 : mh.msg_iov = iov;
1088 :
1089 2 : if (sendmsg(resolve->fds[REQUEST_SEND_FD], &mh, MSG_NOSIGNAL) < 0) {
1090 0 : sd_resolve_query_unref(q);
1091 0 : return -errno;
1092 : }
1093 :
1094 2 : resolve->n_outstanding++;
1095 :
1096 2 : if (_q)
1097 1 : *_q = q;
1098 :
1099 2 : return 0;
1100 : }
1101 :
1102 1 : static int getaddrinfo_done(sd_resolve_query* q) {
1103 1 : assert(q);
1104 1 : assert(q->done);
1105 1 : assert(q->getaddrinfo_handler);
1106 :
1107 1 : errno = q->_errno;
1108 1 : h_errno = q->_h_errno;
1109 :
1110 1 : return q->getaddrinfo_handler(q, q->ret, q->addrinfo, q->userdata);
1111 : }
1112 :
1113 1 : _public_ int sd_resolve_getnameinfo(
1114 : sd_resolve *resolve,
1115 : sd_resolve_query**_q,
1116 : const struct sockaddr *sa, socklen_t salen,
1117 : int flags,
1118 : uint64_t get,
1119 : sd_resolve_getnameinfo_handler_t callback,
1120 : void *userdata) {
1121 :
1122 1 : NameInfoRequest req = {};
1123 1 : struct msghdr mh = {};
1124 : struct iovec iov[2];
1125 : sd_resolve_query *q;
1126 : int r;
1127 :
1128 1 : assert_return(resolve, -EINVAL);
1129 1 : assert_return(sa, -EINVAL);
1130 1 : assert_return(salen >= sizeof(struct sockaddr), -EINVAL);
1131 1 : assert_return(salen <= sizeof(union sockaddr_union), -EINVAL);
1132 1 : assert_return((get & ~SD_RESOLVE_GET_BOTH) == 0, -EINVAL);
1133 1 : assert_return(callback, -EINVAL);
1134 1 : assert_return(!resolve_pid_changed(resolve), -ECHILD);
1135 :
1136 1 : r = alloc_query(resolve, !_q, &q);
1137 1 : if (r < 0)
1138 0 : return r;
1139 :
1140 1 : q->type = REQUEST_NAMEINFO;
1141 1 : q->getnameinfo_handler = callback;
1142 1 : q->userdata = userdata;
1143 :
1144 1 : req.header.id = q->id;
1145 1 : req.header.type = REQUEST_NAMEINFO;
1146 1 : req.header.length = sizeof(NameInfoRequest) + salen;
1147 :
1148 1 : req.flags = flags;
1149 1 : req.sockaddr_len = salen;
1150 1 : req.gethost = !!(get & SD_RESOLVE_GET_HOST);
1151 1 : req.getserv = !!(get & SD_RESOLVE_GET_SERVICE);
1152 :
1153 1 : iov[0] = (struct iovec) { .iov_base = &req, .iov_len = sizeof(NameInfoRequest) };
1154 1 : iov[1] = (struct iovec) { .iov_base = (void*) sa, .iov_len = salen };
1155 :
1156 1 : mh.msg_iov = iov;
1157 1 : mh.msg_iovlen = 2;
1158 :
1159 1 : if (sendmsg(resolve->fds[REQUEST_SEND_FD], &mh, MSG_NOSIGNAL) < 0) {
1160 0 : sd_resolve_query_unref(q);
1161 0 : return -errno;
1162 : }
1163 :
1164 1 : resolve->n_outstanding++;
1165 :
1166 1 : if (_q)
1167 1 : *_q = q;
1168 :
1169 1 : return 0;
1170 : }
1171 :
1172 1 : static int getnameinfo_done(sd_resolve_query *q) {
1173 :
1174 1 : assert(q);
1175 1 : assert(q->done);
1176 1 : assert(q->getnameinfo_handler);
1177 :
1178 1 : errno = q->_errno;
1179 1 : h_errno= q->_h_errno;
1180 :
1181 1 : return q->getnameinfo_handler(q, q->ret, q->host, q->serv, q->userdata);
1182 : }
1183 :
1184 1 : static int resolve_res(
1185 : sd_resolve *resolve,
1186 : sd_resolve_query **_q,
1187 : QueryType qtype,
1188 : const char *dname,
1189 : int class, int type,
1190 : sd_resolve_res_handler_t callback, void *userdata) {
1191 :
1192 1 : struct msghdr mh = {};
1193 : struct iovec iov[2];
1194 1 : ResRequest req = {};
1195 : sd_resolve_query *q;
1196 : int r;
1197 :
1198 1 : assert_return(resolve, -EINVAL);
1199 1 : assert_return(dname, -EINVAL);
1200 1 : assert_return(callback, -EINVAL);
1201 1 : assert_return(!resolve_pid_changed(resolve), -ECHILD);
1202 :
1203 1 : r = alloc_query(resolve, !_q, &q);
1204 1 : if (r < 0)
1205 0 : return r;
1206 :
1207 1 : q->type = qtype;
1208 1 : q->res_handler = callback;
1209 1 : q->userdata = userdata;
1210 :
1211 1 : req.dname_len = strlen(dname) + 1;
1212 1 : req.class = class;
1213 1 : req.type = type;
1214 :
1215 1 : req.header.id = q->id;
1216 1 : req.header.type = qtype;
1217 1 : req.header.length = sizeof(ResRequest) + req.dname_len;
1218 :
1219 1 : iov[0] = (struct iovec) { .iov_base = &req, .iov_len = sizeof(ResRequest) };
1220 1 : iov[1] = (struct iovec) { .iov_base = (void*) dname, .iov_len = req.dname_len };
1221 :
1222 1 : mh.msg_iov = iov;
1223 1 : mh.msg_iovlen = 2;
1224 :
1225 1 : if (sendmsg(resolve->fds[REQUEST_SEND_FD], &mh, MSG_NOSIGNAL) < 0) {
1226 0 : sd_resolve_query_unref(q);
1227 0 : return -errno;
1228 : }
1229 :
1230 1 : resolve->n_outstanding++;
1231 :
1232 1 : if (_q)
1233 1 : *_q = q;
1234 :
1235 1 : return 0;
1236 : }
1237 :
1238 1 : _public_ int sd_resolve_res_query(sd_resolve *resolve, sd_resolve_query** q, const char *dname, int class, int type, sd_resolve_res_handler_t callback, void *userdata) {
1239 1 : return resolve_res(resolve, q, REQUEST_RES_QUERY, dname, class, type, callback, userdata);
1240 : }
1241 :
1242 0 : _public_ int sd_resolve_res_search(sd_resolve *resolve, sd_resolve_query** q, const char *dname, int class, int type, sd_resolve_res_handler_t callback, void *userdata) {
1243 0 : return resolve_res(resolve, q, REQUEST_RES_SEARCH, dname, class, type, callback, userdata);
1244 : }
1245 :
1246 1 : static int res_query_done(sd_resolve_query* q) {
1247 1 : assert(q);
1248 1 : assert(q->done);
1249 1 : assert(q->res_handler);
1250 :
1251 1 : errno = q->_errno;
1252 1 : h_errno = q->_h_errno;
1253 :
1254 1 : return q->res_handler(q, q->ret, q->answer, q->userdata);
1255 : }
1256 :
1257 3 : _public_ sd_resolve_query* sd_resolve_query_ref(sd_resolve_query *q) {
1258 3 : assert_return(q, NULL);
1259 :
1260 3 : assert(q->n_ref >= 1);
1261 3 : q->n_ref++;
1262 :
1263 3 : return q;
1264 : }
1265 :
1266 4 : static void resolve_freeaddrinfo(struct addrinfo *ai) {
1267 10 : while (ai) {
1268 2 : struct addrinfo *next = ai->ai_next;
1269 :
1270 2 : free(ai->ai_addr);
1271 2 : free(ai->ai_canonname);
1272 2 : free(ai);
1273 2 : ai = next;
1274 : }
1275 4 : }
1276 :
1277 5 : static void resolve_query_disconnect(sd_resolve_query *q) {
1278 : sd_resolve *resolve;
1279 : unsigned i;
1280 :
1281 5 : assert(q);
1282 :
1283 5 : if (!q->resolve)
1284 1 : return;
1285 :
1286 4 : resolve = q->resolve;
1287 4 : assert(resolve->n_queries > 0);
1288 :
1289 4 : if (q->done) {
1290 3 : assert(resolve->n_done > 0);
1291 3 : resolve->n_done--;
1292 : }
1293 :
1294 4 : i = q->id % QUERIES_MAX;
1295 4 : assert(resolve->query_array[i] == q);
1296 4 : resolve->query_array[i] = NULL;
1297 4 : LIST_REMOVE(queries, resolve->queries, q);
1298 4 : resolve->n_queries--;
1299 :
1300 4 : q->resolve = NULL;
1301 4 : if (!q->floating)
1302 3 : sd_resolve_unref(resolve);
1303 : }
1304 :
1305 4 : static void resolve_query_free(sd_resolve_query *q) {
1306 4 : assert(q);
1307 :
1308 4 : resolve_query_disconnect(q);
1309 :
1310 4 : resolve_freeaddrinfo(q->addrinfo);
1311 4 : free(q->host);
1312 4 : free(q->serv);
1313 4 : free(q->answer);
1314 4 : free(q);
1315 4 : }
1316 :
1317 7 : _public_ sd_resolve_query* sd_resolve_query_unref(sd_resolve_query* q) {
1318 7 : if (!q)
1319 0 : return NULL;
1320 :
1321 7 : assert(q->n_ref >= 1);
1322 7 : q->n_ref--;
1323 :
1324 7 : if (q->n_ref <= 0)
1325 4 : resolve_query_free(q);
1326 :
1327 7 : return NULL;
1328 : }
1329 :
1330 6 : _public_ int sd_resolve_query_is_done(sd_resolve_query *q) {
1331 6 : assert_return(q, -EINVAL);
1332 6 : assert_return(!resolve_pid_changed(q->resolve), -ECHILD);
1333 :
1334 6 : return q->done;
1335 : }
1336 :
1337 0 : _public_ void* sd_resolve_query_set_userdata(sd_resolve_query *q, void *userdata) {
1338 : void *ret;
1339 :
1340 0 : assert_return(q, NULL);
1341 0 : assert_return(!resolve_pid_changed(q->resolve), NULL);
1342 :
1343 0 : ret = q->userdata;
1344 0 : q->userdata = userdata;
1345 :
1346 0 : return ret;
1347 : }
1348 :
1349 0 : _public_ void* sd_resolve_query_get_userdata(sd_resolve_query *q) {
1350 0 : assert_return(q, NULL);
1351 0 : assert_return(!resolve_pid_changed(q->resolve), NULL);
1352 :
1353 0 : return q->userdata;
1354 : }
1355 :
1356 0 : _public_ sd_resolve *sd_resolve_query_get_resolve(sd_resolve_query *q) {
1357 0 : assert_return(q, NULL);
1358 0 : assert_return(!resolve_pid_changed(q->resolve), NULL);
1359 :
1360 0 : return q->resolve;
1361 : }
1362 :
1363 0 : static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
1364 0 : sd_resolve *resolve = userdata;
1365 : int r;
1366 :
1367 0 : assert(resolve);
1368 :
1369 0 : r = sd_resolve_process(resolve);
1370 0 : if (r < 0)
1371 0 : return r;
1372 :
1373 0 : return 1;
1374 : }
1375 :
1376 0 : _public_ int sd_resolve_attach_event(sd_resolve *resolve, sd_event *event, int priority) {
1377 : int r;
1378 :
1379 0 : assert_return(resolve, -EINVAL);
1380 0 : assert_return(!resolve->event, -EBUSY);
1381 :
1382 0 : assert(!resolve->event_source);
1383 :
1384 0 : if (event)
1385 0 : resolve->event = sd_event_ref(event);
1386 : else {
1387 0 : r = sd_event_default(&resolve->event);
1388 0 : if (r < 0)
1389 0 : return r;
1390 : }
1391 :
1392 0 : r = sd_event_add_io(resolve->event, &resolve->event_source, resolve->fds[RESPONSE_RECV_FD], POLLIN, io_callback, resolve);
1393 0 : if (r < 0)
1394 0 : goto fail;
1395 :
1396 0 : r = sd_event_source_set_priority(resolve->event_source, priority);
1397 0 : if (r < 0)
1398 0 : goto fail;
1399 :
1400 0 : return 0;
1401 :
1402 : fail:
1403 0 : sd_resolve_detach_event(resolve);
1404 0 : return r;
1405 : }
1406 :
1407 1 : _public_ int sd_resolve_detach_event(sd_resolve *resolve) {
1408 1 : assert_return(resolve, -EINVAL);
1409 :
1410 1 : if (!resolve->event)
1411 1 : return 0;
1412 :
1413 0 : if (resolve->event_source) {
1414 0 : sd_event_source_set_enabled(resolve->event_source, SD_EVENT_OFF);
1415 0 : resolve->event_source = sd_event_source_unref(resolve->event_source);
1416 : }
1417 :
1418 0 : resolve->event = sd_event_unref(resolve->event);
1419 0 : return 1;
1420 : }
1421 :
1422 0 : _public_ sd_event *sd_resolve_get_event(sd_resolve *resolve) {
1423 0 : assert_return(resolve, NULL);
1424 :
1425 0 : return resolve->event;
1426 : }
|