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