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