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