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