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