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