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