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