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