]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-resolve/sd-resolve.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / libsystemd / sd-resolve / sd-resolve.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
e963e3ad 2/***
edc6f2f5 3 This file is part of systemd.
e963e3ad
DB
4
5 Copyright 2005-2008 Lennart Poettering
6
edc6f2f5
TG
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
e963e3ad 11
edc6f2f5 12 systemd is distributed in the hope that it will be useful, but
e963e3ad
DB
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
edc6f2f5
TG
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
e963e3ad 20
e963e3ad 21#include <errno.h>
07630cea
LP
22#include <poll.h>
23#include <pthread.h>
e963e3ad 24#include <resolv.h>
07630cea 25#include <signal.h>
e963e3ad 26#include <stdint.h>
07630cea
LP
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
e963e3ad 30#include <sys/prctl.h>
07630cea
LP
31#include <unistd.h>
32
33#include "sd-resolve.h"
e963e3ad 34
b5efdb8a 35#include "alloc-util.h"
3ffd4af2 36#include "fd-util.h"
c004493c 37#include "io-util.h"
968d3d24 38#include "list.h"
93f1bcf4 39#include "missing.h"
07630cea
LP
40#include "socket-util.h"
41#include "util.h"
e963e3ad 42
93f1bcf4
LP
43#define WORKERS_MIN 1U
44#define WORKERS_MAX 16U
45#define QUERIES_MAX 256U
46#define BUFSIZE 10240U
e963e3ad
DB
47
48typedef enum {
49 REQUEST_ADDRINFO,
50 RESPONSE_ADDRINFO,
51 REQUEST_NAMEINFO,
52 RESPONSE_NAMEINFO,
e963e3ad
DB
53 REQUEST_TERMINATE,
54 RESPONSE_DIED
5599e866 55} QueryType;
e963e3ad
DB
56
57enum {
968d3d24
LP
58 REQUEST_RECV_FD,
59 REQUEST_SEND_FD,
60 RESPONSE_RECV_FD,
61 RESPONSE_SEND_FD,
62 _FD_MAX
e963e3ad
DB
63};
64
3bedba4a 65struct sd_resolve {
93f1bcf4
LP
66 unsigned n_ref;
67
968d3d24
LP
68 bool dead:1;
69 pid_t original_pid;
e963e3ad 70
968d3d24 71 int fds[_FD_MAX];
e963e3ad 72
968d3d24
LP
73 pthread_t workers[WORKERS_MAX];
74 unsigned n_valid_workers;
e963e3ad 75
85529c81 76 unsigned current_id;
4a134c49 77 sd_resolve_query* query_array[QUERIES_MAX];
96c76ac4 78 unsigned n_queries, n_done, n_outstanding;
93f1bcf4
LP
79
80 sd_event_source *event_source;
81 sd_event *event;
e963e3ad 82
93f1bcf4
LP
83 sd_resolve_query *current;
84
85 sd_resolve **default_resolve_ptr;
86 pid_t tid;
4a134c49
LP
87
88 LIST_HEAD(sd_resolve_query, queries);
e963e3ad
DB
89};
90
3bedba4a 91struct sd_resolve_query {
93f1bcf4
LP
92 unsigned n_ref;
93
4f809256 94 sd_resolve *resolve;
93f1bcf4
LP
95
96 QueryType type:4;
968d3d24 97 bool done:1;
4a134c49 98 bool floating:1;
e963e3ad 99 unsigned id;
968d3d24 100
e963e3ad
DB
101 int ret;
102 int _errno;
103 int _h_errno;
104 struct addrinfo *addrinfo;
105 char *serv, *host;
968d3d24 106
93f1bcf4
LP
107 union {
108 sd_resolve_getaddrinfo_handler_t getaddrinfo_handler;
109 sd_resolve_getnameinfo_handler_t getnameinfo_handler;
93f1bcf4 110 };
968d3d24 111
93f1bcf4 112 void *userdata;
4a134c49
LP
113
114 LIST_FIELDS(sd_resolve_query, queries);
e963e3ad
DB
115};
116
5599e866
DB
117typedef struct RHeader {
118 QueryType type;
e963e3ad
DB
119 unsigned id;
120 size_t length;
5599e866 121} RHeader;
e963e3ad 122
5599e866
DB
123typedef struct AddrInfoRequest {
124 struct RHeader header;
968d3d24 125 bool hints_valid;
e963e3ad
DB
126 int ai_flags;
127 int ai_family;
128 int ai_socktype;
129 int ai_protocol;
130 size_t node_len, service_len;
5599e866 131} AddrInfoRequest;
e963e3ad 132
5599e866
DB
133typedef struct AddrInfoResponse {
134 struct RHeader header;
e963e3ad
DB
135 int ret;
136 int _errno;
137 int _h_errno;
138 /* followed by addrinfo_serialization[] */
5599e866 139} AddrInfoResponse;
e963e3ad 140
5599e866 141typedef struct AddrInfoSerialization {
e963e3ad
DB
142 int ai_flags;
143 int ai_family;
144 int ai_socktype;
145 int ai_protocol;
146 size_t ai_addrlen;
147 size_t canonname_len;
148 /* Followed by ai_addr amd ai_canonname with variable lengths */
5599e866 149} AddrInfoSerialization;
e963e3ad 150
5599e866
DB
151typedef struct NameInfoRequest {
152 struct RHeader header;
e963e3ad
DB
153 int flags;
154 socklen_t sockaddr_len;
968d3d24 155 bool gethost:1, getserv:1;
5599e866 156} NameInfoRequest;
e963e3ad 157
5599e866
DB
158typedef struct NameInfoResponse {
159 struct RHeader header;
e963e3ad
DB
160 size_t hostlen, servlen;
161 int ret;
162 int _errno;
163 int _h_errno;
5599e866 164} NameInfoResponse;
e963e3ad 165
5599e866
DB
166typedef union Packet {
167 RHeader rheader;
168 AddrInfoRequest addrinfo_request;
169 AddrInfoResponse addrinfo_response;
170 NameInfoRequest nameinfo_request;
171 NameInfoResponse nameinfo_response;
5599e866 172} Packet;
e963e3ad 173
93f1bcf4
LP
174static int getaddrinfo_done(sd_resolve_query* q);
175static int getnameinfo_done(sd_resolve_query *q);
93f1bcf4 176
4a134c49
LP
177static void resolve_query_disconnect(sd_resolve_query *q);
178
93f1bcf4 179#define RESOLVE_DONT_DESTROY(resolve) \
4afd3348 180 _cleanup_(sd_resolve_unrefp) _unused_ sd_resolve *_dont_destroy_##resolve = sd_resolve_ref(resolve)
93f1bcf4 181
e963e3ad 182static int send_died(int out_fd) {
968d3d24 183
93f1bcf4
LP
184 RHeader rh = {
185 .type = RESPONSE_DIED,
186 .length = sizeof(RHeader),
187 };
e963e3ad 188
93f1bcf4 189 assert(out_fd >= 0);
e963e3ad 190
968d3d24
LP
191 if (send(out_fd, &rh, rh.length, MSG_NOSIGNAL) < 0)
192 return -errno;
193
194 return 0;
e963e3ad
DB
195}
196
197static void *serialize_addrinfo(void *p, const struct addrinfo *ai, size_t *length, size_t maxlength) {
5599e866 198 AddrInfoSerialization s;
e963e3ad 199 size_t cnl, l;
968d3d24 200
e963e3ad
DB
201 assert(p);
202 assert(ai);
203 assert(length);
204 assert(*length <= maxlength);
205
968d3d24 206 cnl = ai->ai_canonname ? strlen(ai->ai_canonname)+1 : 0;
5599e866 207 l = sizeof(AddrInfoSerialization) + ai->ai_addrlen + cnl;
e963e3ad
DB
208
209 if (*length + l > maxlength)
210 return NULL;
211
212 s.ai_flags = ai->ai_flags;
213 s.ai_family = ai->ai_family;
214 s.ai_socktype = ai->ai_socktype;
215 s.ai_protocol = ai->ai_protocol;
216 s.ai_addrlen = ai->ai_addrlen;
217 s.canonname_len = cnl;
218
5599e866
DB
219 memcpy((uint8_t*) p, &s, sizeof(AddrInfoSerialization));
220 memcpy((uint8_t*) p + sizeof(AddrInfoSerialization), ai->ai_addr, ai->ai_addrlen);
75f32f04
ZJS
221 memcpy_safe((char*) p + sizeof(AddrInfoSerialization) + ai->ai_addrlen,
222 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 */
79d62972 407 (void) 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
313cefa1 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
df0ff127 463 return r->original_pid != getpid_cached();
968d3d24 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 476 resolve->n_ref = 1;
df0ff127 477 resolve->original_pid = getpid_cached();
93f1bcf4 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
9d4e7d13
ZJS
583 /* Now terminate them and wait until they are gone.
584 If we get an error than most likely the thread already exited. */
5263a45b 585 for (i = 0; i < resolve->n_valid_workers; i++)
9d4e7d13 586 (void) pthread_join(resolve->workers[i], NULL);
e963e3ad
DB
587
588 /* Close all communication channels */
3a1707ff 589 close_many(resolve->fds, _FD_MAX);
3bedba4a 590 free(resolve);
93f1bcf4
LP
591}
592
593_public_ sd_resolve* sd_resolve_ref(sd_resolve *resolve) {
594 assert_return(resolve, NULL);
595
596 assert(resolve->n_ref >= 1);
597 resolve->n_ref++;
598
599 return resolve;
600}
601
602_public_ sd_resolve* sd_resolve_unref(sd_resolve *resolve) {
603
604 if (!resolve)
605 return NULL;
606
607 assert(resolve->n_ref >= 1);
608 resolve->n_ref--;
609
610 if (resolve->n_ref <= 0)
611 resolve_free(resolve);
612
968d3d24 613 return NULL;
e963e3ad
DB
614}
615
968d3d24
LP
616_public_ int sd_resolve_get_fd(sd_resolve *resolve) {
617 assert_return(resolve, -EINVAL);
618 assert_return(!resolve_pid_changed(resolve), -ECHILD);
e963e3ad 619
3bedba4a 620 return resolve->fds[RESPONSE_RECV_FD];
e963e3ad
DB
621}
622
968d3d24
LP
623_public_ int sd_resolve_get_events(sd_resolve *resolve) {
624 assert_return(resolve, -EINVAL);
625 assert_return(!resolve_pid_changed(resolve), -ECHILD);
626
627 return resolve->n_queries > resolve->n_done ? POLLIN : 0;
628}
629
630_public_ int sd_resolve_get_timeout(sd_resolve *resolve, uint64_t *usec) {
631 assert_return(resolve, -EINVAL);
632 assert_return(usec, -EINVAL);
633 assert_return(!resolve_pid_changed(resolve), -ECHILD);
634
635 *usec = (uint64_t) -1;
636 return 0;
637}
638
4f809256
DB
639static sd_resolve_query *lookup_query(sd_resolve *resolve, unsigned id) {
640 sd_resolve_query *q;
968d3d24 641
3bedba4a 642 assert(resolve);
e963e3ad 643
4a134c49 644 q = resolve->query_array[id % QUERIES_MAX];
8e50b5a7 645 if (q)
e963e3ad
DB
646 if (q->id == id)
647 return q;
648
649 return NULL;
650}
651
93f1bcf4
LP
652static int complete_query(sd_resolve *resolve, sd_resolve_query *q) {
653 int r;
654
e963e3ad
DB
655 assert(q);
656 assert(!q->done);
93f1bcf4 657 assert(q->resolve == resolve);
e963e3ad 658
968d3d24 659 q->done = true;
313cefa1 660 resolve->n_done++;
93f1bcf4 661
73dec319 662 resolve->current = sd_resolve_query_ref(q);
93f1bcf4
LP
663
664 switch (q->type) {
665
666 case REQUEST_ADDRINFO:
667 r = getaddrinfo_done(q);
668 break;
669
670 case REQUEST_NAMEINFO:
671 r = getnameinfo_done(q);
672 break;
673
93f1bcf4
LP
674 default:
675 assert_not_reached("Cannot complete unknown query type");
676 }
677
502fe44e 678 resolve->current = NULL;
93f1bcf4 679
4a134c49
LP
680 if (q->floating) {
681 resolve_query_disconnect(q);
f2e2415d 682 sd_resolve_query_unref(q);
4a134c49
LP
683 }
684
502fe44e
LP
685 sd_resolve_query_unref(q);
686
93f1bcf4 687 return r;
e963e3ad
DB
688}
689
968d3d24 690static int unserialize_addrinfo(const void **p, size_t *length, struct addrinfo **ret_ai) {
5599e866 691 AddrInfoSerialization s;
e963e3ad
DB
692 size_t l;
693 struct addrinfo *ai;
968d3d24 694
e963e3ad 695 assert(p);
968d3d24 696 assert(*p);
e963e3ad
DB
697 assert(ret_ai);
698 assert(length);
699
5599e866 700 if (*length < sizeof(AddrInfoSerialization))
968d3d24 701 return -EBADMSG;
e963e3ad 702
968d3d24 703 memcpy(&s, *p, sizeof(s));
e963e3ad 704
5599e866 705 l = sizeof(AddrInfoSerialization) + s.ai_addrlen + s.canonname_len;
e963e3ad 706 if (*length < l)
968d3d24 707 return -EBADMSG;
e963e3ad 708
968d3d24 709 ai = new0(struct addrinfo, 1);
8e50b5a7 710 if (!ai)
968d3d24 711 return -ENOMEM;
e963e3ad
DB
712
713 ai->ai_flags = s.ai_flags;
714 ai->ai_family = s.ai_family;
715 ai->ai_socktype = s.ai_socktype;
716 ai->ai_protocol = s.ai_protocol;
717 ai->ai_addrlen = s.ai_addrlen;
718
968d3d24
LP
719 if (s.ai_addrlen > 0) {
720 ai->ai_addr = memdup((const uint8_t*) *p + sizeof(AddrInfoSerialization), s.ai_addrlen);
721 if (!ai->ai_addr) {
722 free(ai);
723 return -ENOMEM;
724 }
725 }
e963e3ad 726
968d3d24
LP
727 if (s.canonname_len > 0) {
728 ai->ai_canonname = memdup((const uint8_t*) *p + sizeof(AddrInfoSerialization) + s.ai_addrlen, s.canonname_len);
729 if (!ai->ai_canonname) {
730 free(ai->ai_addr);
731 free(ai);
732 return -ENOMEM;
733 }
734 }
e963e3ad
DB
735
736 *length -= l;
737 *ret_ai = ai;
968d3d24 738 *p = ((const uint8_t*) *p) + l;
e963e3ad 739
968d3d24 740 return 0;
e963e3ad
DB
741}
742
5599e866
DB
743static int handle_response(sd_resolve *resolve, const Packet *packet, size_t length) {
744 const RHeader *resp;
4f809256 745 sd_resolve_query *q;
968d3d24 746 int r;
e963e3ad 747
3bedba4a 748 assert(resolve);
e963e3ad
DB
749
750 resp = &packet->rheader;
751 assert(resp);
5599e866 752 assert(length >= sizeof(RHeader));
e963e3ad
DB
753 assert(length == resp->length);
754
755 if (resp->type == RESPONSE_DIED) {
968d3d24 756 resolve->dead = true;
e963e3ad
DB
757 return 0;
758 }
759
96c76ac4
LP
760 assert(resolve->n_outstanding > 0);
761 resolve->n_outstanding--;
762
3bedba4a 763 q = lookup_query(resolve, resp->id);
8e50b5a7 764 if (!q)
e963e3ad
DB
765 return 0;
766
767 switch (resp->type) {
968d3d24 768
e963e3ad 769 case RESPONSE_ADDRINFO: {
5599e866 770 const AddrInfoResponse *ai_resp = &packet->addrinfo_response;
e963e3ad
DB
771 const void *p;
772 size_t l;
773 struct addrinfo *prev = NULL;
774
5599e866 775 assert(length >= sizeof(AddrInfoResponse));
e963e3ad
DB
776 assert(q->type == REQUEST_ADDRINFO);
777
778 q->ret = ai_resp->ret;
779 q->_errno = ai_resp->_errno;
780 q->_h_errno = ai_resp->_h_errno;
968d3d24 781
5599e866
DB
782 l = length - sizeof(AddrInfoResponse);
783 p = (const uint8_t*) resp + sizeof(AddrInfoResponse);
e963e3ad
DB
784
785 while (l > 0 && p) {
786 struct addrinfo *ai = NULL;
e963e3ad 787
968d3d24
LP
788 r = unserialize_addrinfo(&p, &l, &ai);
789 if (r < 0) {
790 q->ret = EAI_SYSTEM;
791 q->_errno = -r;
792 q->_h_errno = 0;
793 freeaddrinfo(q->addrinfo);
794 q->addrinfo = NULL;
e963e3ad
DB
795 break;
796 }
797
798 if (prev)
799 prev->ai_next = ai;
800 else
801 q->addrinfo = ai;
802
803 prev = ai;
804 }
805
93f1bcf4 806 return complete_query(resolve, q);
e963e3ad
DB
807 }
808
809 case RESPONSE_NAMEINFO: {
5599e866 810 const NameInfoResponse *ni_resp = &packet->nameinfo_response;
e963e3ad 811
5599e866 812 assert(length >= sizeof(NameInfoResponse));
e963e3ad
DB
813 assert(q->type == REQUEST_NAMEINFO);
814
815 q->ret = ni_resp->ret;
816 q->_errno = ni_resp->_errno;
817 q->_h_errno = ni_resp->_h_errno;
818
968d3d24
LP
819 if (ni_resp->hostlen > 0) {
820 q->host = strndup((const char*) ni_resp + sizeof(NameInfoResponse), ni_resp->hostlen-1);
821 if (!q->host) {
e963e3ad 822 q->ret = EAI_MEMORY;
968d3d24
LP
823 q->_errno = ENOMEM;
824 q->_h_errno = 0;
825 }
826 }
e963e3ad 827
968d3d24
LP
828 if (ni_resp->servlen > 0) {
829 q->serv = strndup((const char*) ni_resp + sizeof(NameInfoResponse) + ni_resp->hostlen, ni_resp->servlen-1);
830 if (!q->serv) {
e963e3ad 831 q->ret = EAI_MEMORY;
968d3d24
LP
832 q->_errno = ENOMEM;
833 q->_h_errno = 0;
834 }
835 }
e963e3ad 836
93f1bcf4 837 return complete_query(resolve, q);
e963e3ad
DB
838 }
839
e963e3ad 840 default:
93f1bcf4 841 return 0;
e963e3ad 842 }
e963e3ad
DB
843}
844
968d3d24 845_public_ int sd_resolve_process(sd_resolve *resolve) {
93f1bcf4
LP
846 RESOLVE_DONT_DESTROY(resolve);
847
848 union {
849 Packet packet;
850 uint8_t space[BUFSIZE];
851 } buf;
852 ssize_t l;
853 int r;
968d3d24
LP
854
855 assert_return(resolve, -EINVAL);
856 assert_return(!resolve_pid_changed(resolve), -ECHILD);
e963e3ad 857
93f1bcf4
LP
858 /* We don't allow recursively invoking sd_resolve_process(). */
859 assert_return(!resolve->current, -EBUSY);
e963e3ad 860
93f1bcf4
LP
861 l = recv(resolve->fds[RESPONSE_RECV_FD], &buf, sizeof(buf), 0);
862 if (l < 0) {
863 if (errno == EAGAIN)
864 return 0;
968d3d24 865
93f1bcf4
LP
866 return -errno;
867 }
868 if (l == 0)
869 return -ECONNREFUSED;
e963e3ad 870
93f1bcf4
LP
871 r = handle_response(resolve, &buf.packet, (size_t) l);
872 if (r < 0)
873 return r;
e963e3ad 874
93f1bcf4 875 return 1;
968d3d24 876}
e963e3ad 877
968d3d24
LP
878_public_ int sd_resolve_wait(sd_resolve *resolve, uint64_t timeout_usec) {
879 int r;
e963e3ad 880
968d3d24
LP
881 assert_return(resolve, -EINVAL);
882 assert_return(!resolve_pid_changed(resolve), -ECHILD);
e963e3ad 883
93f1bcf4 884 if (resolve->n_done >= resolve->n_queries)
968d3d24 885 return 0;
e963e3ad 886
968d3d24
LP
887 do {
888 r = fd_wait_for_event(resolve->fds[RESPONSE_RECV_FD], POLLIN, timeout_usec);
889 } while (r == -EINTR);
e963e3ad 890
968d3d24
LP
891 if (r < 0)
892 return r;
e963e3ad 893
968d3d24 894 return sd_resolve_process(resolve);
e963e3ad
DB
895}
896
4a134c49 897static int alloc_query(sd_resolve *resolve, bool floating, sd_resolve_query **_q) {
4f809256 898 sd_resolve_query *q;
968d3d24
LP
899 int r;
900
3bedba4a 901 assert(resolve);
968d3d24 902 assert(_q);
e963e3ad 903
968d3d24
LP
904 if (resolve->n_queries >= QUERIES_MAX)
905 return -ENOBUFS;
906
907 r = start_threads(resolve, 1);
908 if (r < 0)
909 return r;
e963e3ad 910
85529c81 911 while (resolve->query_array[resolve->current_id % QUERIES_MAX])
3bedba4a 912 resolve->current_id++;
e963e3ad 913
85529c81 914 q = resolve->query_array[resolve->current_id % QUERIES_MAX] = new0(sd_resolve_query, 1);
968d3d24
LP
915 if (!q)
916 return -ENOMEM;
e963e3ad 917
93f1bcf4 918 q->n_ref = 1;
4a134c49
LP
919 q->resolve = resolve;
920 q->floating = floating;
85529c81 921 q->id = resolve->current_id++;
968d3d24 922
4a134c49
LP
923 if (!floating)
924 sd_resolve_ref(resolve);
925
926 LIST_PREPEND(queries, resolve->queries, q);
93f1bcf4
LP
927 resolve->n_queries++;
928
968d3d24
LP
929 *_q = q;
930 return 0;
e963e3ad
DB
931}
932
968d3d24
LP
933_public_ int sd_resolve_getaddrinfo(
934 sd_resolve *resolve,
151b9b96 935 sd_resolve_query **_q,
93f1bcf4
LP
936 const char *node, const char *service,
937 const struct addrinfo *hints,
938 sd_resolve_getaddrinfo_handler_t callback, void *userdata) {
968d3d24
LP
939
940 AddrInfoRequest req = {};
941 struct msghdr mh = {};
942 struct iovec iov[3];
4f809256 943 sd_resolve_query *q;
968d3d24 944 int r;
e963e3ad 945
968d3d24 946 assert_return(resolve, -EINVAL);
93f1bcf4
LP
947 assert_return(node || service, -EINVAL);
948 assert_return(callback, -EINVAL);
968d3d24 949 assert_return(!resolve_pid_changed(resolve), -ECHILD);
e963e3ad 950
4a134c49 951 r = alloc_query(resolve, !_q, &q);
968d3d24
LP
952 if (r < 0)
953 return r;
e963e3ad 954
93f1bcf4
LP
955 q->type = REQUEST_ADDRINFO;
956 q->getaddrinfo_handler = callback;
957 q->userdata = userdata;
958
968d3d24
LP
959 req.node_len = node ? strlen(node)+1 : 0;
960 req.service_len = service ? strlen(service)+1 : 0;
e963e3ad 961
968d3d24 962 req.header.id = q->id;
93f1bcf4 963 req.header.type = REQUEST_ADDRINFO;
968d3d24 964 req.header.length = sizeof(AddrInfoRequest) + req.node_len + req.service_len;
e963e3ad 965
968d3d24
LP
966 if (hints) {
967 req.hints_valid = true;
968 req.ai_flags = hints->ai_flags;
969 req.ai_family = hints->ai_family;
970 req.ai_socktype = hints->ai_socktype;
971 req.ai_protocol = hints->ai_protocol;
e963e3ad
DB
972 }
973
968d3d24 974 iov[mh.msg_iovlen++] = (struct iovec) { .iov_base = &req, .iov_len = sizeof(AddrInfoRequest) };
e963e3ad 975 if (node)
968d3d24 976 iov[mh.msg_iovlen++] = (struct iovec) { .iov_base = (void*) node, .iov_len = req.node_len };
e963e3ad 977 if (service)
968d3d24 978 iov[mh.msg_iovlen++] = (struct iovec) { .iov_base = (void*) service, .iov_len = req.service_len };
968d3d24 979 mh.msg_iov = iov;
e963e3ad 980
968d3d24 981 if (sendmsg(resolve->fds[REQUEST_SEND_FD], &mh, MSG_NOSIGNAL) < 0) {
93f1bcf4 982 sd_resolve_query_unref(q);
968d3d24
LP
983 return -errno;
984 }
e963e3ad 985
96c76ac4
LP
986 resolve->n_outstanding++;
987
4a134c49
LP
988 if (_q)
989 *_q = q;
990
968d3d24 991 return 0;
e963e3ad
DB
992}
993
93f1bcf4
LP
994static int getaddrinfo_done(sd_resolve_query* q) {
995 assert(q);
996 assert(q->done);
997 assert(q->getaddrinfo_handler);
e963e3ad 998
93f1bcf4
LP
999 errno = q->_errno;
1000 h_errno = q->_h_errno;
e963e3ad 1001
93f1bcf4 1002 return q->getaddrinfo_handler(q, q->ret, q->addrinfo, q->userdata);
e963e3ad
DB
1003}
1004
968d3d24
LP
1005_public_ int sd_resolve_getnameinfo(
1006 sd_resolve *resolve,
151b9b96 1007 sd_resolve_query**_q,
968d3d24
LP
1008 const struct sockaddr *sa, socklen_t salen,
1009 int flags,
93f1bcf4
LP
1010 uint64_t get,
1011 sd_resolve_getnameinfo_handler_t callback,
1012 void *userdata) {
e963e3ad 1013
968d3d24
LP
1014 NameInfoRequest req = {};
1015 struct msghdr mh = {};
1016 struct iovec iov[2];
1017 sd_resolve_query *q;
1018 int r;
e963e3ad 1019
968d3d24
LP
1020 assert_return(resolve, -EINVAL);
1021 assert_return(sa, -EINVAL);
1022 assert_return(salen >= sizeof(struct sockaddr), -EINVAL);
1023 assert_return(salen <= sizeof(union sockaddr_union), -EINVAL);
93f1bcf4
LP
1024 assert_return((get & ~SD_RESOLVE_GET_BOTH) == 0, -EINVAL);
1025 assert_return(callback, -EINVAL);
968d3d24 1026 assert_return(!resolve_pid_changed(resolve), -ECHILD);
e963e3ad 1027
4a134c49 1028 r = alloc_query(resolve, !_q, &q);
968d3d24
LP
1029 if (r < 0)
1030 return r;
e963e3ad 1031
93f1bcf4
LP
1032 q->type = REQUEST_NAMEINFO;
1033 q->getnameinfo_handler = callback;
1034 q->userdata = userdata;
1035
968d3d24 1036 req.header.id = q->id;
93f1bcf4 1037 req.header.type = REQUEST_NAMEINFO;
968d3d24 1038 req.header.length = sizeof(NameInfoRequest) + salen;
e963e3ad 1039
968d3d24
LP
1040 req.flags = flags;
1041 req.sockaddr_len = salen;
93f1bcf4
LP
1042 req.gethost = !!(get & SD_RESOLVE_GET_HOST);
1043 req.getserv = !!(get & SD_RESOLVE_GET_SERVICE);
e963e3ad 1044
968d3d24
LP
1045 iov[0] = (struct iovec) { .iov_base = &req, .iov_len = sizeof(NameInfoRequest) };
1046 iov[1] = (struct iovec) { .iov_base = (void*) sa, .iov_len = salen };
e963e3ad 1047
968d3d24
LP
1048 mh.msg_iov = iov;
1049 mh.msg_iovlen = 2;
e963e3ad 1050
968d3d24 1051 if (sendmsg(resolve->fds[REQUEST_SEND_FD], &mh, MSG_NOSIGNAL) < 0) {
93f1bcf4 1052 sd_resolve_query_unref(q);
968d3d24
LP
1053 return -errno;
1054 }
e963e3ad 1055
96c76ac4
LP
1056 resolve->n_outstanding++;
1057
4a134c49
LP
1058 if (_q)
1059 *_q = q;
1060
968d3d24 1061 return 0;
e963e3ad
DB
1062}
1063
93f1bcf4 1064static int getnameinfo_done(sd_resolve_query *q) {
968d3d24 1065
93f1bcf4
LP
1066 assert(q);
1067 assert(q->done);
1068 assert(q->getnameinfo_handler);
e963e3ad 1069
93f1bcf4
LP
1070 errno = q->_errno;
1071 h_errno= q->_h_errno;
e963e3ad 1072
93f1bcf4 1073 return q->getnameinfo_handler(q, q->ret, q->host, q->serv, q->userdata);
e963e3ad
DB
1074}
1075
93f1bcf4
LP
1076_public_ sd_resolve_query* sd_resolve_query_ref(sd_resolve_query *q) {
1077 assert_return(q, NULL);
e963e3ad 1078
93f1bcf4
LP
1079 assert(q->n_ref >= 1);
1080 q->n_ref++;
968d3d24 1081
93f1bcf4 1082 return q;
e963e3ad
DB
1083}
1084
93f1bcf4
LP
1085static void resolve_freeaddrinfo(struct addrinfo *ai) {
1086 while (ai) {
1087 struct addrinfo *next = ai->ai_next;
e963e3ad 1088
93f1bcf4
LP
1089 free(ai->ai_addr);
1090 free(ai->ai_canonname);
1091 free(ai);
1092 ai = next;
1093 }
1094}
e963e3ad 1095
4a134c49
LP
1096static void resolve_query_disconnect(sd_resolve_query *q) {
1097 sd_resolve *resolve;
93f1bcf4 1098 unsigned i;
e963e3ad 1099
93f1bcf4 1100 assert(q);
4a134c49
LP
1101
1102 if (!q->resolve)
1103 return;
1104
1105 resolve = q->resolve;
1106 assert(resolve->n_queries > 0);
e963e3ad 1107
968d3d24 1108 if (q->done) {
4a134c49
LP
1109 assert(resolve->n_done > 0);
1110 resolve->n_done--;
e963e3ad
DB
1111 }
1112
968d3d24 1113 i = q->id % QUERIES_MAX;
4a134c49
LP
1114 assert(resolve->query_array[i] == q);
1115 resolve->query_array[i] = NULL;
1116 LIST_REMOVE(queries, resolve->queries, q);
1117 resolve->n_queries--;
1118
1119 q->resolve = NULL;
1120 if (!q->floating)
1121 sd_resolve_unref(resolve);
1122}
1123
1124static void resolve_query_free(sd_resolve_query *q) {
1125 assert(q);
1126
1127 resolve_query_disconnect(q);
e963e3ad 1128
93f1bcf4 1129 resolve_freeaddrinfo(q->addrinfo);
e963e3ad
DB
1130 free(q->host);
1131 free(q->serv);
e963e3ad 1132 free(q);
e963e3ad
DB
1133}
1134
93f1bcf4
LP
1135_public_ sd_resolve_query* sd_resolve_query_unref(sd_resolve_query* q) {
1136 if (!q)
1137 return NULL;
e963e3ad 1138
93f1bcf4
LP
1139 assert(q->n_ref >= 1);
1140 q->n_ref--;
e963e3ad 1141
93f1bcf4
LP
1142 if (q->n_ref <= 0)
1143 resolve_query_free(q);
e963e3ad 1144
93f1bcf4 1145 return NULL;
e963e3ad
DB
1146}
1147
93f1bcf4 1148_public_ int sd_resolve_query_is_done(sd_resolve_query *q) {
968d3d24
LP
1149 assert_return(q, -EINVAL);
1150 assert_return(!resolve_pid_changed(q->resolve), -ECHILD);
e963e3ad
DB
1151
1152 return q->done;
1153}
1154
93f1bcf4 1155_public_ void* sd_resolve_query_set_userdata(sd_resolve_query *q, void *userdata) {
968d3d24 1156 void *ret;
e963e3ad 1157
968d3d24
LP
1158 assert_return(q, NULL);
1159 assert_return(!resolve_pid_changed(q->resolve), NULL);
1160
1161 ret = q->userdata;
e963e3ad 1162 q->userdata = userdata;
968d3d24
LP
1163
1164 return ret;
e963e3ad
DB
1165}
1166
93f1bcf4 1167_public_ void* sd_resolve_query_get_userdata(sd_resolve_query *q) {
968d3d24
LP
1168 assert_return(q, NULL);
1169 assert_return(!resolve_pid_changed(q->resolve), NULL);
e963e3ad
DB
1170
1171 return q->userdata;
1172}
93f1bcf4
LP
1173
1174_public_ sd_resolve *sd_resolve_query_get_resolve(sd_resolve_query *q) {
1175 assert_return(q, NULL);
1176 assert_return(!resolve_pid_changed(q->resolve), NULL);
1177
1178 return q->resolve;
1179}
1180
1181static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
1182 sd_resolve *resolve = userdata;
1183 int r;
1184
1185 assert(resolve);
1186
1187 r = sd_resolve_process(resolve);
1188 if (r < 0)
1189 return r;
1190
1191 return 1;
1192}
1193
32d20645 1194_public_ int sd_resolve_attach_event(sd_resolve *resolve, sd_event *event, int64_t priority) {
93f1bcf4
LP
1195 int r;
1196
1197 assert_return(resolve, -EINVAL);
1198 assert_return(!resolve->event, -EBUSY);
1199
1200 assert(!resolve->event_source);
1201
1202 if (event)
1203 resolve->event = sd_event_ref(event);
1204 else {
1205 r = sd_event_default(&resolve->event);
1206 if (r < 0)
1207 return r;
1208 }
1209
1210 r = sd_event_add_io(resolve->event, &resolve->event_source, resolve->fds[RESPONSE_RECV_FD], POLLIN, io_callback, resolve);
1211 if (r < 0)
1212 goto fail;
1213
1214 r = sd_event_source_set_priority(resolve->event_source, priority);
1215 if (r < 0)
1216 goto fail;
1217
1218 return 0;
1219
1220fail:
1221 sd_resolve_detach_event(resolve);
1222 return r;
1223}
1224
1225_public_ int sd_resolve_detach_event(sd_resolve *resolve) {
1226 assert_return(resolve, -EINVAL);
1227
1228 if (!resolve->event)
1229 return 0;
1230
1231 if (resolve->event_source) {
1232 sd_event_source_set_enabled(resolve->event_source, SD_EVENT_OFF);
1233 resolve->event_source = sd_event_source_unref(resolve->event_source);
1234 }
1235
1236 resolve->event = sd_event_unref(resolve->event);
1237 return 1;
1238}
1239
1240_public_ sd_event *sd_resolve_get_event(sd_resolve *resolve) {
1241 assert_return(resolve, NULL);
1242
1243 return resolve->event;
1244}