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