]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-resolve/sd-resolve.c
util-lib: split out IO related calls to io-util.[ch]
[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
3ffd4af2 36#include "fd-util.h"
c004493c 37#include "io-util.h"
968d3d24 38#include "list.h"
93f1bcf4
LP
39#include "missing.h"
40#include "resolve-util.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
LP
180#define RESOLVE_DONT_DESTROY(resolve) \
181 _cleanup_resolve_unref_ _unused_ sd_resolve *_dont_destroy_##resolve = sd_resolve_ref(resolve)
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. */
968d3d24 586 for (i = 0; i < resolve->n_valid_workers; i++) {
e963e3ad 587 for (;;) {
968d3d24 588 if (pthread_join(resolve->workers[i], NULL) != EINTR)
e963e3ad
DB
589 break;
590 }
591 }
592
593 /* Close all communication channels */
968d3d24 594 for (i = 0; i < _FD_MAX; i++)
03e334a1 595 safe_close(resolve->fds[i]);
e963e3ad 596
3bedba4a 597 free(resolve);
93f1bcf4
LP
598}
599
600_public_ sd_resolve* sd_resolve_ref(sd_resolve *resolve) {
601 assert_return(resolve, NULL);
602
603 assert(resolve->n_ref >= 1);
604 resolve->n_ref++;
605
606 return resolve;
607}
608
609_public_ sd_resolve* sd_resolve_unref(sd_resolve *resolve) {
610
611 if (!resolve)
612 return NULL;
613
614 assert(resolve->n_ref >= 1);
615 resolve->n_ref--;
616
617 if (resolve->n_ref <= 0)
618 resolve_free(resolve);
619
968d3d24 620 return NULL;
e963e3ad
DB
621}
622
968d3d24
LP
623_public_ int sd_resolve_get_fd(sd_resolve *resolve) {
624 assert_return(resolve, -EINVAL);
625 assert_return(!resolve_pid_changed(resolve), -ECHILD);
e963e3ad 626
3bedba4a 627 return resolve->fds[RESPONSE_RECV_FD];
e963e3ad
DB
628}
629
968d3d24
LP
630_public_ int sd_resolve_get_events(sd_resolve *resolve) {
631 assert_return(resolve, -EINVAL);
632 assert_return(!resolve_pid_changed(resolve), -ECHILD);
633
634 return resolve->n_queries > resolve->n_done ? POLLIN : 0;
635}
636
637_public_ int sd_resolve_get_timeout(sd_resolve *resolve, uint64_t *usec) {
638 assert_return(resolve, -EINVAL);
639 assert_return(usec, -EINVAL);
640 assert_return(!resolve_pid_changed(resolve), -ECHILD);
641
642 *usec = (uint64_t) -1;
643 return 0;
644}
645
4f809256
DB
646static sd_resolve_query *lookup_query(sd_resolve *resolve, unsigned id) {
647 sd_resolve_query *q;
968d3d24 648
3bedba4a 649 assert(resolve);
e963e3ad 650
4a134c49 651 q = resolve->query_array[id % QUERIES_MAX];
8e50b5a7 652 if (q)
e963e3ad
DB
653 if (q->id == id)
654 return q;
655
656 return NULL;
657}
658
93f1bcf4
LP
659static int complete_query(sd_resolve *resolve, sd_resolve_query *q) {
660 int r;
661
e963e3ad
DB
662 assert(q);
663 assert(!q->done);
93f1bcf4 664 assert(q->resolve == resolve);
e963e3ad 665
968d3d24 666 q->done = true;
93f1bcf4
LP
667 resolve->n_done ++;
668
73dec319 669 resolve->current = sd_resolve_query_ref(q);
93f1bcf4
LP
670
671 switch (q->type) {
672
673 case REQUEST_ADDRINFO:
674 r = getaddrinfo_done(q);
675 break;
676
677 case REQUEST_NAMEINFO:
678 r = getnameinfo_done(q);
679 break;
680
93f1bcf4
LP
681 default:
682 assert_not_reached("Cannot complete unknown query type");
683 }
684
502fe44e 685 resolve->current = NULL;
93f1bcf4 686
4a134c49
LP
687 if (q->floating) {
688 resolve_query_disconnect(q);
f2e2415d 689 sd_resolve_query_unref(q);
4a134c49
LP
690 }
691
502fe44e
LP
692 sd_resolve_query_unref(q);
693
93f1bcf4 694 return r;
e963e3ad
DB
695}
696
968d3d24 697static int unserialize_addrinfo(const void **p, size_t *length, struct addrinfo **ret_ai) {
5599e866 698 AddrInfoSerialization s;
e963e3ad
DB
699 size_t l;
700 struct addrinfo *ai;
968d3d24 701
e963e3ad 702 assert(p);
968d3d24 703 assert(*p);
e963e3ad
DB
704 assert(ret_ai);
705 assert(length);
706
5599e866 707 if (*length < sizeof(AddrInfoSerialization))
968d3d24 708 return -EBADMSG;
e963e3ad 709
968d3d24 710 memcpy(&s, *p, sizeof(s));
e963e3ad 711
5599e866 712 l = sizeof(AddrInfoSerialization) + s.ai_addrlen + s.canonname_len;
e963e3ad 713 if (*length < l)
968d3d24 714 return -EBADMSG;
e963e3ad 715
968d3d24 716 ai = new0(struct addrinfo, 1);
8e50b5a7 717 if (!ai)
968d3d24 718 return -ENOMEM;
e963e3ad
DB
719
720 ai->ai_flags = s.ai_flags;
721 ai->ai_family = s.ai_family;
722 ai->ai_socktype = s.ai_socktype;
723 ai->ai_protocol = s.ai_protocol;
724 ai->ai_addrlen = s.ai_addrlen;
725
968d3d24
LP
726 if (s.ai_addrlen > 0) {
727 ai->ai_addr = memdup((const uint8_t*) *p + sizeof(AddrInfoSerialization), s.ai_addrlen);
728 if (!ai->ai_addr) {
729 free(ai);
730 return -ENOMEM;
731 }
732 }
e963e3ad 733
968d3d24
LP
734 if (s.canonname_len > 0) {
735 ai->ai_canonname = memdup((const uint8_t*) *p + sizeof(AddrInfoSerialization) + s.ai_addrlen, s.canonname_len);
736 if (!ai->ai_canonname) {
737 free(ai->ai_addr);
738 free(ai);
739 return -ENOMEM;
740 }
741 }
e963e3ad
DB
742
743 *length -= l;
744 *ret_ai = ai;
968d3d24 745 *p = ((const uint8_t*) *p) + l;
e963e3ad 746
968d3d24 747 return 0;
e963e3ad
DB
748}
749
5599e866
DB
750static int handle_response(sd_resolve *resolve, const Packet *packet, size_t length) {
751 const RHeader *resp;
4f809256 752 sd_resolve_query *q;
968d3d24 753 int r;
e963e3ad 754
3bedba4a 755 assert(resolve);
e963e3ad
DB
756
757 resp = &packet->rheader;
758 assert(resp);
5599e866 759 assert(length >= sizeof(RHeader));
e963e3ad
DB
760 assert(length == resp->length);
761
762 if (resp->type == RESPONSE_DIED) {
968d3d24 763 resolve->dead = true;
e963e3ad
DB
764 return 0;
765 }
766
96c76ac4
LP
767 assert(resolve->n_outstanding > 0);
768 resolve->n_outstanding--;
769
3bedba4a 770 q = lookup_query(resolve, resp->id);
8e50b5a7 771 if (!q)
e963e3ad
DB
772 return 0;
773
774 switch (resp->type) {
968d3d24 775
e963e3ad 776 case RESPONSE_ADDRINFO: {
5599e866 777 const AddrInfoResponse *ai_resp = &packet->addrinfo_response;
e963e3ad
DB
778 const void *p;
779 size_t l;
780 struct addrinfo *prev = NULL;
781
5599e866 782 assert(length >= sizeof(AddrInfoResponse));
e963e3ad
DB
783 assert(q->type == REQUEST_ADDRINFO);
784
785 q->ret = ai_resp->ret;
786 q->_errno = ai_resp->_errno;
787 q->_h_errno = ai_resp->_h_errno;
968d3d24 788
5599e866
DB
789 l = length - sizeof(AddrInfoResponse);
790 p = (const uint8_t*) resp + sizeof(AddrInfoResponse);
e963e3ad
DB
791
792 while (l > 0 && p) {
793 struct addrinfo *ai = NULL;
e963e3ad 794
968d3d24
LP
795 r = unserialize_addrinfo(&p, &l, &ai);
796 if (r < 0) {
797 q->ret = EAI_SYSTEM;
798 q->_errno = -r;
799 q->_h_errno = 0;
800 freeaddrinfo(q->addrinfo);
801 q->addrinfo = NULL;
e963e3ad
DB
802 break;
803 }
804
805 if (prev)
806 prev->ai_next = ai;
807 else
808 q->addrinfo = ai;
809
810 prev = ai;
811 }
812
93f1bcf4 813 return complete_query(resolve, q);
e963e3ad
DB
814 }
815
816 case RESPONSE_NAMEINFO: {
5599e866 817 const NameInfoResponse *ni_resp = &packet->nameinfo_response;
e963e3ad 818
5599e866 819 assert(length >= sizeof(NameInfoResponse));
e963e3ad
DB
820 assert(q->type == REQUEST_NAMEINFO);
821
822 q->ret = ni_resp->ret;
823 q->_errno = ni_resp->_errno;
824 q->_h_errno = ni_resp->_h_errno;
825
968d3d24
LP
826 if (ni_resp->hostlen > 0) {
827 q->host = strndup((const char*) ni_resp + sizeof(NameInfoResponse), ni_resp->hostlen-1);
828 if (!q->host) {
e963e3ad 829 q->ret = EAI_MEMORY;
968d3d24
LP
830 q->_errno = ENOMEM;
831 q->_h_errno = 0;
832 }
833 }
e963e3ad 834
968d3d24
LP
835 if (ni_resp->servlen > 0) {
836 q->serv = strndup((const char*) ni_resp + sizeof(NameInfoResponse) + ni_resp->hostlen, ni_resp->servlen-1);
837 if (!q->serv) {
e963e3ad 838 q->ret = EAI_MEMORY;
968d3d24
LP
839 q->_errno = ENOMEM;
840 q->_h_errno = 0;
841 }
842 }
e963e3ad 843
93f1bcf4 844 return complete_query(resolve, q);
e963e3ad
DB
845 }
846
e963e3ad 847 default:
93f1bcf4 848 return 0;
e963e3ad 849 }
e963e3ad
DB
850}
851
968d3d24 852_public_ int sd_resolve_process(sd_resolve *resolve) {
93f1bcf4
LP
853 RESOLVE_DONT_DESTROY(resolve);
854
855 union {
856 Packet packet;
857 uint8_t space[BUFSIZE];
858 } buf;
859 ssize_t l;
860 int r;
968d3d24
LP
861
862 assert_return(resolve, -EINVAL);
863 assert_return(!resolve_pid_changed(resolve), -ECHILD);
e963e3ad 864
93f1bcf4
LP
865 /* We don't allow recursively invoking sd_resolve_process(). */
866 assert_return(!resolve->current, -EBUSY);
e963e3ad 867
93f1bcf4
LP
868 l = recv(resolve->fds[RESPONSE_RECV_FD], &buf, sizeof(buf), 0);
869 if (l < 0) {
870 if (errno == EAGAIN)
871 return 0;
968d3d24 872
93f1bcf4
LP
873 return -errno;
874 }
875 if (l == 0)
876 return -ECONNREFUSED;
e963e3ad 877
93f1bcf4
LP
878 r = handle_response(resolve, &buf.packet, (size_t) l);
879 if (r < 0)
880 return r;
e963e3ad 881
93f1bcf4 882 return 1;
968d3d24 883}
e963e3ad 884
968d3d24
LP
885_public_ int sd_resolve_wait(sd_resolve *resolve, uint64_t timeout_usec) {
886 int r;
e963e3ad 887
968d3d24
LP
888 assert_return(resolve, -EINVAL);
889 assert_return(!resolve_pid_changed(resolve), -ECHILD);
e963e3ad 890
93f1bcf4 891 if (resolve->n_done >= resolve->n_queries)
968d3d24 892 return 0;
e963e3ad 893
968d3d24
LP
894 do {
895 r = fd_wait_for_event(resolve->fds[RESPONSE_RECV_FD], POLLIN, timeout_usec);
896 } while (r == -EINTR);
e963e3ad 897
968d3d24
LP
898 if (r < 0)
899 return r;
e963e3ad 900
968d3d24 901 return sd_resolve_process(resolve);
e963e3ad
DB
902}
903
4a134c49 904static int alloc_query(sd_resolve *resolve, bool floating, sd_resolve_query **_q) {
4f809256 905 sd_resolve_query *q;
968d3d24
LP
906 int r;
907
3bedba4a 908 assert(resolve);
968d3d24 909 assert(_q);
e963e3ad 910
968d3d24
LP
911 if (resolve->n_queries >= QUERIES_MAX)
912 return -ENOBUFS;
913
914 r = start_threads(resolve, 1);
915 if (r < 0)
916 return r;
e963e3ad 917
85529c81 918 while (resolve->query_array[resolve->current_id % QUERIES_MAX])
3bedba4a 919 resolve->current_id++;
e963e3ad 920
85529c81 921 q = resolve->query_array[resolve->current_id % QUERIES_MAX] = new0(sd_resolve_query, 1);
968d3d24
LP
922 if (!q)
923 return -ENOMEM;
e963e3ad 924
93f1bcf4 925 q->n_ref = 1;
4a134c49
LP
926 q->resolve = resolve;
927 q->floating = floating;
85529c81 928 q->id = resolve->current_id++;
968d3d24 929
4a134c49
LP
930 if (!floating)
931 sd_resolve_ref(resolve);
932
933 LIST_PREPEND(queries, resolve->queries, q);
93f1bcf4
LP
934 resolve->n_queries++;
935
968d3d24
LP
936 *_q = q;
937 return 0;
e963e3ad
DB
938}
939
968d3d24
LP
940_public_ int sd_resolve_getaddrinfo(
941 sd_resolve *resolve,
151b9b96 942 sd_resolve_query **_q,
93f1bcf4
LP
943 const char *node, const char *service,
944 const struct addrinfo *hints,
945 sd_resolve_getaddrinfo_handler_t callback, void *userdata) {
968d3d24
LP
946
947 AddrInfoRequest req = {};
948 struct msghdr mh = {};
949 struct iovec iov[3];
4f809256 950 sd_resolve_query *q;
968d3d24 951 int r;
e963e3ad 952
968d3d24 953 assert_return(resolve, -EINVAL);
93f1bcf4
LP
954 assert_return(node || service, -EINVAL);
955 assert_return(callback, -EINVAL);
968d3d24 956 assert_return(!resolve_pid_changed(resolve), -ECHILD);
e963e3ad 957
4a134c49 958 r = alloc_query(resolve, !_q, &q);
968d3d24
LP
959 if (r < 0)
960 return r;
e963e3ad 961
93f1bcf4
LP
962 q->type = REQUEST_ADDRINFO;
963 q->getaddrinfo_handler = callback;
964 q->userdata = userdata;
965
968d3d24
LP
966 req.node_len = node ? strlen(node)+1 : 0;
967 req.service_len = service ? strlen(service)+1 : 0;
e963e3ad 968
968d3d24 969 req.header.id = q->id;
93f1bcf4 970 req.header.type = REQUEST_ADDRINFO;
968d3d24 971 req.header.length = sizeof(AddrInfoRequest) + req.node_len + req.service_len;
e963e3ad 972
968d3d24
LP
973 if (hints) {
974 req.hints_valid = true;
975 req.ai_flags = hints->ai_flags;
976 req.ai_family = hints->ai_family;
977 req.ai_socktype = hints->ai_socktype;
978 req.ai_protocol = hints->ai_protocol;
e963e3ad
DB
979 }
980
968d3d24 981 iov[mh.msg_iovlen++] = (struct iovec) { .iov_base = &req, .iov_len = sizeof(AddrInfoRequest) };
e963e3ad 982 if (node)
968d3d24 983 iov[mh.msg_iovlen++] = (struct iovec) { .iov_base = (void*) node, .iov_len = req.node_len };
e963e3ad 984 if (service)
968d3d24 985 iov[mh.msg_iovlen++] = (struct iovec) { .iov_base = (void*) service, .iov_len = req.service_len };
968d3d24 986 mh.msg_iov = iov;
e963e3ad 987
968d3d24 988 if (sendmsg(resolve->fds[REQUEST_SEND_FD], &mh, MSG_NOSIGNAL) < 0) {
93f1bcf4 989 sd_resolve_query_unref(q);
968d3d24
LP
990 return -errno;
991 }
e963e3ad 992
96c76ac4
LP
993 resolve->n_outstanding++;
994
4a134c49
LP
995 if (_q)
996 *_q = q;
997
968d3d24 998 return 0;
e963e3ad
DB
999}
1000
93f1bcf4
LP
1001static int getaddrinfo_done(sd_resolve_query* q) {
1002 assert(q);
1003 assert(q->done);
1004 assert(q->getaddrinfo_handler);
e963e3ad 1005
93f1bcf4
LP
1006 errno = q->_errno;
1007 h_errno = q->_h_errno;
e963e3ad 1008
93f1bcf4 1009 return q->getaddrinfo_handler(q, q->ret, q->addrinfo, q->userdata);
e963e3ad
DB
1010}
1011
968d3d24
LP
1012_public_ int sd_resolve_getnameinfo(
1013 sd_resolve *resolve,
151b9b96 1014 sd_resolve_query**_q,
968d3d24
LP
1015 const struct sockaddr *sa, socklen_t salen,
1016 int flags,
93f1bcf4
LP
1017 uint64_t get,
1018 sd_resolve_getnameinfo_handler_t callback,
1019 void *userdata) {
e963e3ad 1020
968d3d24
LP
1021 NameInfoRequest req = {};
1022 struct msghdr mh = {};
1023 struct iovec iov[2];
1024 sd_resolve_query *q;
1025 int r;
e963e3ad 1026
968d3d24
LP
1027 assert_return(resolve, -EINVAL);
1028 assert_return(sa, -EINVAL);
1029 assert_return(salen >= sizeof(struct sockaddr), -EINVAL);
1030 assert_return(salen <= sizeof(union sockaddr_union), -EINVAL);
93f1bcf4
LP
1031 assert_return((get & ~SD_RESOLVE_GET_BOTH) == 0, -EINVAL);
1032 assert_return(callback, -EINVAL);
968d3d24 1033 assert_return(!resolve_pid_changed(resolve), -ECHILD);
e963e3ad 1034
4a134c49 1035 r = alloc_query(resolve, !_q, &q);
968d3d24
LP
1036 if (r < 0)
1037 return r;
e963e3ad 1038
93f1bcf4
LP
1039 q->type = REQUEST_NAMEINFO;
1040 q->getnameinfo_handler = callback;
1041 q->userdata = userdata;
1042
968d3d24 1043 req.header.id = q->id;
93f1bcf4 1044 req.header.type = REQUEST_NAMEINFO;
968d3d24 1045 req.header.length = sizeof(NameInfoRequest) + salen;
e963e3ad 1046
968d3d24
LP
1047 req.flags = flags;
1048 req.sockaddr_len = salen;
93f1bcf4
LP
1049 req.gethost = !!(get & SD_RESOLVE_GET_HOST);
1050 req.getserv = !!(get & SD_RESOLVE_GET_SERVICE);
e963e3ad 1051
968d3d24
LP
1052 iov[0] = (struct iovec) { .iov_base = &req, .iov_len = sizeof(NameInfoRequest) };
1053 iov[1] = (struct iovec) { .iov_base = (void*) sa, .iov_len = salen };
e963e3ad 1054
968d3d24
LP
1055 mh.msg_iov = iov;
1056 mh.msg_iovlen = 2;
e963e3ad 1057
968d3d24 1058 if (sendmsg(resolve->fds[REQUEST_SEND_FD], &mh, MSG_NOSIGNAL) < 0) {
93f1bcf4 1059 sd_resolve_query_unref(q);
968d3d24
LP
1060 return -errno;
1061 }
e963e3ad 1062
96c76ac4
LP
1063 resolve->n_outstanding++;
1064
4a134c49
LP
1065 if (_q)
1066 *_q = q;
1067
968d3d24 1068 return 0;
e963e3ad
DB
1069}
1070
93f1bcf4 1071static int getnameinfo_done(sd_resolve_query *q) {
968d3d24 1072
93f1bcf4
LP
1073 assert(q);
1074 assert(q->done);
1075 assert(q->getnameinfo_handler);
e963e3ad 1076
93f1bcf4
LP
1077 errno = q->_errno;
1078 h_errno= q->_h_errno;
e963e3ad 1079
93f1bcf4 1080 return q->getnameinfo_handler(q, q->ret, q->host, q->serv, q->userdata);
e963e3ad
DB
1081}
1082
93f1bcf4
LP
1083_public_ sd_resolve_query* sd_resolve_query_ref(sd_resolve_query *q) {
1084 assert_return(q, NULL);
e963e3ad 1085
93f1bcf4
LP
1086 assert(q->n_ref >= 1);
1087 q->n_ref++;
968d3d24 1088
93f1bcf4 1089 return q;
e963e3ad
DB
1090}
1091
93f1bcf4
LP
1092static void resolve_freeaddrinfo(struct addrinfo *ai) {
1093 while (ai) {
1094 struct addrinfo *next = ai->ai_next;
e963e3ad 1095
93f1bcf4
LP
1096 free(ai->ai_addr);
1097 free(ai->ai_canonname);
1098 free(ai);
1099 ai = next;
1100 }
1101}
e963e3ad 1102
4a134c49
LP
1103static void resolve_query_disconnect(sd_resolve_query *q) {
1104 sd_resolve *resolve;
93f1bcf4 1105 unsigned i;
e963e3ad 1106
93f1bcf4 1107 assert(q);
4a134c49
LP
1108
1109 if (!q->resolve)
1110 return;
1111
1112 resolve = q->resolve;
1113 assert(resolve->n_queries > 0);
e963e3ad 1114
968d3d24 1115 if (q->done) {
4a134c49
LP
1116 assert(resolve->n_done > 0);
1117 resolve->n_done--;
e963e3ad
DB
1118 }
1119
968d3d24 1120 i = q->id % QUERIES_MAX;
4a134c49
LP
1121 assert(resolve->query_array[i] == q);
1122 resolve->query_array[i] = NULL;
1123 LIST_REMOVE(queries, resolve->queries, q);
1124 resolve->n_queries--;
1125
1126 q->resolve = NULL;
1127 if (!q->floating)
1128 sd_resolve_unref(resolve);
1129}
1130
1131static void resolve_query_free(sd_resolve_query *q) {
1132 assert(q);
1133
1134 resolve_query_disconnect(q);
e963e3ad 1135
93f1bcf4 1136 resolve_freeaddrinfo(q->addrinfo);
e963e3ad
DB
1137 free(q->host);
1138 free(q->serv);
e963e3ad 1139 free(q);
e963e3ad
DB
1140}
1141
93f1bcf4
LP
1142_public_ sd_resolve_query* sd_resolve_query_unref(sd_resolve_query* q) {
1143 if (!q)
1144 return NULL;
e963e3ad 1145
93f1bcf4
LP
1146 assert(q->n_ref >= 1);
1147 q->n_ref--;
e963e3ad 1148
93f1bcf4
LP
1149 if (q->n_ref <= 0)
1150 resolve_query_free(q);
e963e3ad 1151
93f1bcf4 1152 return NULL;
e963e3ad
DB
1153}
1154
93f1bcf4 1155_public_ int sd_resolve_query_is_done(sd_resolve_query *q) {
968d3d24
LP
1156 assert_return(q, -EINVAL);
1157 assert_return(!resolve_pid_changed(q->resolve), -ECHILD);
e963e3ad
DB
1158
1159 return q->done;
1160}
1161
93f1bcf4 1162_public_ void* sd_resolve_query_set_userdata(sd_resolve_query *q, void *userdata) {
968d3d24 1163 void *ret;
e963e3ad 1164
968d3d24
LP
1165 assert_return(q, NULL);
1166 assert_return(!resolve_pid_changed(q->resolve), NULL);
1167
1168 ret = q->userdata;
e963e3ad 1169 q->userdata = userdata;
968d3d24
LP
1170
1171 return ret;
e963e3ad
DB
1172}
1173
93f1bcf4 1174_public_ void* sd_resolve_query_get_userdata(sd_resolve_query *q) {
968d3d24
LP
1175 assert_return(q, NULL);
1176 assert_return(!resolve_pid_changed(q->resolve), NULL);
e963e3ad
DB
1177
1178 return q->userdata;
1179}
93f1bcf4
LP
1180
1181_public_ sd_resolve *sd_resolve_query_get_resolve(sd_resolve_query *q) {
1182 assert_return(q, NULL);
1183 assert_return(!resolve_pid_changed(q->resolve), NULL);
1184
1185 return q->resolve;
1186}
1187
1188static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
1189 sd_resolve *resolve = userdata;
1190 int r;
1191
1192 assert(resolve);
1193
1194 r = sd_resolve_process(resolve);
1195 if (r < 0)
1196 return r;
1197
1198 return 1;
1199}
1200
1201_public_ int sd_resolve_attach_event(sd_resolve *resolve, sd_event *event, int priority) {
1202 int r;
1203
1204 assert_return(resolve, -EINVAL);
1205 assert_return(!resolve->event, -EBUSY);
1206
1207 assert(!resolve->event_source);
1208
1209 if (event)
1210 resolve->event = sd_event_ref(event);
1211 else {
1212 r = sd_event_default(&resolve->event);
1213 if (r < 0)
1214 return r;
1215 }
1216
1217 r = sd_event_add_io(resolve->event, &resolve->event_source, resolve->fds[RESPONSE_RECV_FD], POLLIN, io_callback, resolve);
1218 if (r < 0)
1219 goto fail;
1220
1221 r = sd_event_source_set_priority(resolve->event_source, priority);
1222 if (r < 0)
1223 goto fail;
1224
1225 return 0;
1226
1227fail:
1228 sd_resolve_detach_event(resolve);
1229 return r;
1230}
1231
1232_public_ int sd_resolve_detach_event(sd_resolve *resolve) {
1233 assert_return(resolve, -EINVAL);
1234
1235 if (!resolve->event)
1236 return 0;
1237
1238 if (resolve->event_source) {
1239 sd_event_source_set_enabled(resolve->event_source, SD_EVENT_OFF);
1240 resolve->event_source = sd_event_source_unref(resolve->event_source);
1241 }
1242
1243 resolve->event = sd_event_unref(resolve->event);
1244 return 1;
1245}
1246
1247_public_ sd_event *sd_resolve_get_event(sd_resolve *resolve) {
1248 assert_return(resolve, NULL);
1249
1250 return resolve->event;
1251}