]>
Commit | Line | Data |
---|---|---|
edc6f2f5 TG |
1 | /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ |
2 | ||
e963e3ad | 3 | /*** |
edc6f2f5 | 4 | This file is part of systemd. |
e963e3ad DB |
5 | |
6 | Copyright 2005-2008 Lennart Poettering | |
7 | ||
edc6f2f5 TG |
8 | systemd is free software; you can redistribute it and/or modify it |
9 | under the terms of the GNU Lesser General Public License as published by | |
10 | the Free Software Foundation; either version 2.1 of the License, or | |
11 | (at your option) any later version. | |
e963e3ad | 12 | |
edc6f2f5 | 13 | systemd is distributed in the hope that it will be useful, but |
e963e3ad DB |
14 | WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | Lesser General Public License for more details. | |
17 | ||
edc6f2f5 TG |
18 | You should have received a copy of the GNU Lesser General Public License |
19 | along with systemd; If not, see <http://www.gnu.org/licenses/>. | |
20 | ***/ | |
e963e3ad | 21 | |
e963e3ad DB |
22 | #include <assert.h> |
23 | #include <fcntl.h> | |
24 | #include <signal.h> | |
25 | #include <unistd.h> | |
26 | #include <sys/select.h> | |
27 | #include <stdio.h> | |
28 | #include <string.h> | |
29 | #include <stdlib.h> | |
30 | #include <errno.h> | |
31 | #include <sys/wait.h> | |
32 | #include <sys/types.h> | |
33 | #include <pwd.h> | |
34 | #include <netinet/in.h> | |
35 | #include <arpa/nameser.h> | |
36 | #include <resolv.h> | |
37 | #include <dirent.h> | |
38 | #include <sys/time.h> | |
39 | #include <sys/resource.h> | |
40 | #include <stdint.h> | |
41 | #include <pthread.h> | |
e963e3ad | 42 | #include <sys/prctl.h> |
e963e3ad | 43 | |
3bedba4a | 44 | #include "sd-resolve.h" |
e963e3ad DB |
45 | #include "util.h" |
46 | ||
47 | #define MAX_WORKERS 16 | |
48 | #define MAX_QUERIES 256 | |
49 | #define BUFSIZE (10240) | |
50 | ||
51 | typedef enum { | |
52 | REQUEST_ADDRINFO, | |
53 | RESPONSE_ADDRINFO, | |
54 | REQUEST_NAMEINFO, | |
55 | RESPONSE_NAMEINFO, | |
56 | REQUEST_RES_QUERY, | |
57 | REQUEST_RES_SEARCH, | |
58 | RESPONSE_RES, | |
59 | REQUEST_TERMINATE, | |
60 | RESPONSE_DIED | |
5599e866 | 61 | } QueryType; |
e963e3ad DB |
62 | |
63 | enum { | |
64 | REQUEST_RECV_FD = 0, | |
65 | REQUEST_SEND_FD = 1, | |
66 | RESPONSE_RECV_FD = 2, | |
67 | RESPONSE_SEND_FD = 3, | |
68 | MESSAGE_FD_MAX = 4 | |
69 | }; | |
70 | ||
3bedba4a | 71 | struct sd_resolve { |
e963e3ad DB |
72 | int fds[MESSAGE_FD_MAX]; |
73 | ||
74 | pthread_t workers[MAX_WORKERS]; | |
75 | unsigned valid_workers; | |
76 | ||
77 | unsigned current_id, current_index; | |
4f809256 | 78 | sd_resolve_query* queries[MAX_QUERIES]; |
e963e3ad | 79 | |
4f809256 | 80 | sd_resolve_query *done_head, *done_tail; |
e963e3ad DB |
81 | |
82 | int n_queries; | |
83 | int dead; | |
84 | }; | |
85 | ||
3bedba4a | 86 | struct sd_resolve_query { |
4f809256 | 87 | sd_resolve *resolve; |
e963e3ad DB |
88 | int done; |
89 | unsigned id; | |
5599e866 | 90 | QueryType type; |
4f809256 | 91 | sd_resolve_query *done_next, *done_prev; |
e963e3ad DB |
92 | int ret; |
93 | int _errno; | |
94 | int _h_errno; | |
95 | struct addrinfo *addrinfo; | |
96 | char *serv, *host; | |
97 | void *userdata; | |
98 | }; | |
99 | ||
5599e866 DB |
100 | typedef struct RHeader { |
101 | QueryType type; | |
e963e3ad DB |
102 | unsigned id; |
103 | size_t length; | |
5599e866 | 104 | } RHeader; |
e963e3ad | 105 | |
5599e866 DB |
106 | typedef struct AddrInfoRequest { |
107 | struct RHeader header; | |
e963e3ad DB |
108 | int hints_is_null; |
109 | int ai_flags; | |
110 | int ai_family; | |
111 | int ai_socktype; | |
112 | int ai_protocol; | |
113 | size_t node_len, service_len; | |
5599e866 | 114 | } AddrInfoRequest; |
e963e3ad | 115 | |
5599e866 DB |
116 | typedef struct AddrInfoResponse { |
117 | struct RHeader header; | |
e963e3ad DB |
118 | int ret; |
119 | int _errno; | |
120 | int _h_errno; | |
121 | /* followed by addrinfo_serialization[] */ | |
5599e866 | 122 | } AddrInfoResponse; |
e963e3ad | 123 | |
5599e866 | 124 | typedef struct AddrInfoSerialization { |
e963e3ad DB |
125 | int ai_flags; |
126 | int ai_family; | |
127 | int ai_socktype; | |
128 | int ai_protocol; | |
129 | size_t ai_addrlen; | |
130 | size_t canonname_len; | |
131 | /* Followed by ai_addr amd ai_canonname with variable lengths */ | |
5599e866 | 132 | } AddrInfoSerialization; |
e963e3ad | 133 | |
5599e866 DB |
134 | typedef struct NameInfoRequest { |
135 | struct RHeader header; | |
e963e3ad DB |
136 | int flags; |
137 | socklen_t sockaddr_len; | |
138 | int gethost, getserv; | |
5599e866 | 139 | } NameInfoRequest; |
e963e3ad | 140 | |
5599e866 DB |
141 | typedef struct NameInfoResponse { |
142 | struct RHeader header; | |
e963e3ad DB |
143 | size_t hostlen, servlen; |
144 | int ret; | |
145 | int _errno; | |
146 | int _h_errno; | |
5599e866 | 147 | } NameInfoResponse; |
e963e3ad | 148 | |
5599e866 DB |
149 | typedef struct ResRequest { |
150 | struct RHeader header; | |
e963e3ad DB |
151 | int class; |
152 | int type; | |
153 | size_t dname_len; | |
5599e866 | 154 | } ResRequest; |
e963e3ad | 155 | |
5599e866 DB |
156 | typedef struct ResResponse { |
157 | struct RHeader header; | |
e963e3ad DB |
158 | int ret; |
159 | int _errno; | |
160 | int _h_errno; | |
5599e866 DB |
161 | } ResResponse; |
162 | ||
163 | typedef union Packet { | |
164 | RHeader rheader; | |
165 | AddrInfoRequest addrinfo_request; | |
166 | AddrInfoResponse addrinfo_response; | |
167 | NameInfoRequest nameinfo_request; | |
168 | NameInfoResponse nameinfo_response; | |
169 | ResRequest res_request; | |
170 | ResResponse res_response; | |
171 | } Packet; | |
e963e3ad DB |
172 | |
173 | static int send_died(int out_fd) { | |
5599e866 | 174 | RHeader rh = {}; |
e963e3ad DB |
175 | assert(out_fd > 0); |
176 | ||
177 | rh.type = RESPONSE_DIED; | |
178 | rh.id = 0; | |
179 | rh.length = sizeof(rh); | |
180 | ||
181 | return send(out_fd, &rh, rh.length, MSG_NOSIGNAL); | |
182 | } | |
183 | ||
184 | static void *serialize_addrinfo(void *p, const struct addrinfo *ai, size_t *length, size_t maxlength) { | |
5599e866 | 185 | AddrInfoSerialization s; |
e963e3ad DB |
186 | size_t cnl, l; |
187 | assert(p); | |
188 | assert(ai); | |
189 | assert(length); | |
190 | assert(*length <= maxlength); | |
191 | ||
192 | cnl = (ai->ai_canonname ? strlen(ai->ai_canonname)+1 : 0); | |
5599e866 | 193 | l = sizeof(AddrInfoSerialization) + ai->ai_addrlen + cnl; |
e963e3ad DB |
194 | |
195 | if (*length + l > maxlength) | |
196 | return NULL; | |
197 | ||
198 | s.ai_flags = ai->ai_flags; | |
199 | s.ai_family = ai->ai_family; | |
200 | s.ai_socktype = ai->ai_socktype; | |
201 | s.ai_protocol = ai->ai_protocol; | |
202 | s.ai_addrlen = ai->ai_addrlen; | |
203 | s.canonname_len = cnl; | |
204 | ||
5599e866 DB |
205 | memcpy((uint8_t*) p, &s, sizeof(AddrInfoSerialization)); |
206 | memcpy((uint8_t*) p + sizeof(AddrInfoSerialization), ai->ai_addr, ai->ai_addrlen); | |
e963e3ad DB |
207 | |
208 | if (ai->ai_canonname) | |
5599e866 | 209 | strcpy((char*) p + sizeof(AddrInfoSerialization) + ai->ai_addrlen, ai->ai_canonname); |
e963e3ad DB |
210 | |
211 | *length += l; | |
212 | return (uint8_t*) p + l; | |
213 | } | |
214 | ||
215 | static int send_addrinfo_reply(int out_fd, unsigned id, int ret, struct addrinfo *ai, int _errno, int _h_errno) { | |
5599e866 DB |
216 | AddrInfoResponse data[BUFSIZE/sizeof(AddrInfoResponse) + 1] = {}; |
217 | AddrInfoResponse *resp = data; | |
e963e3ad DB |
218 | assert(out_fd >= 0); |
219 | ||
220 | resp->header.type = RESPONSE_ADDRINFO; | |
221 | resp->header.id = id; | |
5599e866 | 222 | resp->header.length = sizeof(AddrInfoResponse); |
e963e3ad DB |
223 | resp->ret = ret; |
224 | resp->_errno = _errno; | |
225 | resp->_h_errno = _h_errno; | |
226 | ||
227 | if (ret == 0 && ai) { | |
228 | void *p = data + 1; | |
229 | struct addrinfo *k; | |
230 | ||
231 | for (k = ai; k; k = k->ai_next) { | |
8e50b5a7 DB |
232 | p = serialize_addrinfo(p, k, &resp->header.length, (char*) data + BUFSIZE - (char*) p); |
233 | if (!p) { | |
e963e3ad DB |
234 | resp->ret = EAI_MEMORY; |
235 | break; | |
236 | } | |
237 | } | |
238 | } | |
239 | ||
240 | if (ai) | |
241 | freeaddrinfo(ai); | |
242 | ||
243 | return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL); | |
244 | } | |
245 | ||
246 | static int send_nameinfo_reply(int out_fd, unsigned id, int ret, const char *host, const char *serv, int _errno, int _h_errno) { | |
5599e866 | 247 | NameInfoResponse data[BUFSIZE/sizeof(NameInfoResponse) + 1] = {}; |
e963e3ad | 248 | size_t hl, sl; |
5599e866 | 249 | NameInfoResponse *resp = data; |
e963e3ad DB |
250 | |
251 | assert(out_fd >= 0); | |
252 | ||
253 | sl = serv ? strlen(serv)+1 : 0; | |
254 | hl = host ? strlen(host)+1 : 0; | |
255 | ||
256 | resp->header.type = RESPONSE_NAMEINFO; | |
257 | resp->header.id = id; | |
5599e866 | 258 | resp->header.length = sizeof(NameInfoResponse) + hl + sl; |
e963e3ad DB |
259 | resp->ret = ret; |
260 | resp->_errno = _errno; | |
261 | resp->_h_errno = _h_errno; | |
262 | resp->hostlen = hl; | |
263 | resp->servlen = sl; | |
264 | ||
265 | assert(sizeof(data) >= resp->header.length); | |
266 | ||
267 | if (host) | |
5599e866 | 268 | memcpy((uint8_t *)data + sizeof(NameInfoResponse), host, hl); |
e963e3ad DB |
269 | |
270 | if (serv) | |
5599e866 | 271 | memcpy((uint8_t *)data + sizeof(NameInfoResponse) + hl, serv, sl); |
e963e3ad DB |
272 | |
273 | return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL); | |
274 | } | |
275 | ||
276 | static int send_res_reply(int out_fd, unsigned id, const unsigned char *answer, int ret, int _errno, int _h_errno) { | |
5599e866 DB |
277 | ResResponse data[BUFSIZE/sizeof(ResResponse) + 1] = {}; |
278 | ResResponse *resp = data; | |
e963e3ad DB |
279 | |
280 | assert(out_fd >= 0); | |
281 | ||
282 | resp->header.type = RESPONSE_RES; | |
283 | resp->header.id = id; | |
5599e866 | 284 | resp->header.length = sizeof(ResResponse) + (ret < 0 ? 0 : ret); |
e963e3ad DB |
285 | resp->ret = ret; |
286 | resp->_errno = _errno; | |
287 | resp->_h_errno = _h_errno; | |
288 | ||
289 | assert(sizeof(data) >= resp->header.length); | |
290 | ||
291 | if (ret > 0) | |
5599e866 | 292 | memcpy((uint8_t *)data + sizeof(ResResponse), answer, ret); |
e963e3ad DB |
293 | |
294 | return send(out_fd, resp, resp->header.length, MSG_NOSIGNAL); | |
295 | } | |
296 | ||
5599e866 DB |
297 | static int handle_request(int out_fd, const Packet *packet, size_t length) { |
298 | const RHeader *req; | |
e963e3ad DB |
299 | assert(out_fd >= 0); |
300 | ||
301 | req = &packet->rheader; | |
302 | assert(req); | |
5599e866 | 303 | assert(length >= sizeof(RHeader)); |
e963e3ad DB |
304 | assert(length == req->length); |
305 | ||
306 | switch (req->type) { | |
307 | case REQUEST_ADDRINFO: { | |
308 | struct addrinfo ai = {}, *result = NULL; | |
5599e866 | 309 | const AddrInfoRequest *ai_req = &packet->addrinfo_request; |
e963e3ad DB |
310 | const char *node, *service; |
311 | int ret; | |
312 | ||
5599e866 DB |
313 | assert(length >= sizeof(AddrInfoRequest)); |
314 | assert(length == sizeof(AddrInfoRequest) + ai_req->node_len + ai_req->service_len); | |
e963e3ad DB |
315 | |
316 | ai.ai_flags = ai_req->ai_flags; | |
317 | ai.ai_family = ai_req->ai_family; | |
318 | ai.ai_socktype = ai_req->ai_socktype; | |
319 | ai.ai_protocol = ai_req->ai_protocol; | |
320 | ||
5599e866 DB |
321 | node = ai_req->node_len ? (const char*) ai_req + sizeof(AddrInfoRequest) : NULL; |
322 | service = ai_req->service_len ? (const char*) ai_req + sizeof(AddrInfoRequest) + ai_req->node_len : NULL; | |
e963e3ad DB |
323 | |
324 | ret = getaddrinfo(node, service, | |
325 | ai_req->hints_is_null ? NULL : &ai, | |
326 | &result); | |
327 | ||
328 | /* send_addrinfo_reply() frees result */ | |
329 | return send_addrinfo_reply(out_fd, req->id, ret, result, errno, h_errno); | |
330 | } | |
331 | ||
332 | case REQUEST_NAMEINFO: { | |
333 | int ret; | |
5599e866 | 334 | const NameInfoRequest *ni_req = &packet->nameinfo_request; |
e963e3ad DB |
335 | char hostbuf[NI_MAXHOST], servbuf[NI_MAXSERV]; |
336 | struct sockaddr_storage sa; | |
337 | ||
5599e866 DB |
338 | assert(length >= sizeof(NameInfoRequest)); |
339 | assert(length == sizeof(NameInfoRequest) + ni_req->sockaddr_len); | |
e963e3ad | 340 | |
5599e866 | 341 | memcpy(&sa, (const uint8_t *) ni_req + sizeof(NameInfoRequest), ni_req->sockaddr_len); |
e963e3ad DB |
342 | |
343 | ret = getnameinfo((struct sockaddr *)&sa, ni_req->sockaddr_len, | |
344 | ni_req->gethost ? hostbuf : NULL, ni_req->gethost ? sizeof(hostbuf) : 0, | |
345 | ni_req->getserv ? servbuf : NULL, ni_req->getserv ? sizeof(servbuf) : 0, | |
346 | ni_req->flags); | |
347 | ||
348 | return send_nameinfo_reply(out_fd, req->id, ret, | |
349 | ret == 0 && ni_req->gethost ? hostbuf : NULL, | |
350 | ret == 0 && ni_req->getserv ? servbuf : NULL, | |
351 | errno, h_errno); | |
352 | } | |
353 | ||
354 | case REQUEST_RES_QUERY: | |
355 | case REQUEST_RES_SEARCH: { | |
356 | int ret; | |
357 | HEADER answer[BUFSIZE/sizeof(HEADER) + 1]; | |
5599e866 | 358 | const ResRequest *res_req = &packet->res_request; |
e963e3ad DB |
359 | const char *dname; |
360 | ||
5599e866 DB |
361 | assert(length >= sizeof(ResRequest)); |
362 | assert(length == sizeof(ResRequest) + res_req->dname_len); | |
e963e3ad | 363 | |
5599e866 | 364 | dname = (const char *) req + sizeof(ResRequest); |
e963e3ad DB |
365 | |
366 | if (req->type == REQUEST_RES_QUERY) | |
367 | ret = res_query(dname, res_req->class, res_req->type, (unsigned char *) answer, BUFSIZE); | |
368 | else | |
369 | ret = res_search(dname, res_req->class, res_req->type, (unsigned char *) answer, BUFSIZE); | |
370 | ||
371 | return send_res_reply(out_fd, req->id, (unsigned char *) answer, ret, errno, h_errno); | |
372 | } | |
373 | ||
374 | case REQUEST_TERMINATE: | |
375 | /* Quit */ | |
376 | return -1; | |
377 | ||
378 | default: | |
379 | ; | |
380 | } | |
381 | ||
382 | return 0; | |
383 | } | |
384 | ||
385 | static void* thread_worker(void *p) { | |
4f809256 | 386 | sd_resolve *resolve = p; |
e963e3ad DB |
387 | sigset_t fullset; |
388 | ||
389 | /* No signals in this thread please */ | |
390 | sigfillset(&fullset); | |
391 | pthread_sigmask(SIG_BLOCK, &fullset, NULL); | |
392 | ||
3bedba4a | 393 | while (!resolve->dead) { |
5599e866 | 394 | Packet buf[BUFSIZE/sizeof(Packet) + 1]; |
e963e3ad DB |
395 | ssize_t length; |
396 | ||
3bedba4a | 397 | length = recv(resolve->fds[REQUEST_RECV_FD], buf, sizeof(buf), 0); |
e963e3ad DB |
398 | |
399 | if (length <= 0) { | |
400 | if (length < 0 && (errno == EAGAIN || errno == EINTR)) | |
401 | continue; | |
402 | break; | |
403 | } | |
404 | ||
3bedba4a | 405 | if (resolve->dead) |
e963e3ad DB |
406 | break; |
407 | ||
3bedba4a | 408 | if (handle_request(resolve->fds[RESPONSE_SEND_FD], buf, (size_t) length) < 0) |
e963e3ad DB |
409 | break; |
410 | } | |
411 | ||
3bedba4a | 412 | send_died(resolve->fds[RESPONSE_SEND_FD]); |
e963e3ad DB |
413 | |
414 | return NULL; | |
415 | } | |
416 | ||
35bbea48 | 417 | _public_ sd_resolve* sd_resolve_new(unsigned n_proc) { |
4f809256 | 418 | sd_resolve *resolve = NULL; |
8a6233fb | 419 | int i, r; |
e963e3ad DB |
420 | |
421 | assert(n_proc >= 1); | |
422 | ||
423 | if (n_proc > MAX_WORKERS) | |
424 | n_proc = MAX_WORKERS; | |
425 | ||
885d1c80 | 426 | resolve = new(sd_resolve, 1); |
3bedba4a | 427 | if (!resolve) { |
e963e3ad DB |
428 | errno = ENOMEM; |
429 | goto fail; | |
430 | } | |
431 | ||
3bedba4a TG |
432 | resolve->dead = 0; |
433 | resolve->valid_workers = 0; | |
e963e3ad DB |
434 | |
435 | for (i = 0; i < MESSAGE_FD_MAX; i++) | |
3bedba4a | 436 | resolve->fds[i] = -1; |
e963e3ad | 437 | |
3bedba4a | 438 | memset(resolve->queries, 0, sizeof(resolve->queries)); |
e963e3ad | 439 | |
3bedba4a | 440 | r = socketpair(PF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, resolve->fds); |
8a6233fb TG |
441 | if (r < 0) |
442 | goto fail; | |
e963e3ad | 443 | |
3bedba4a | 444 | r = socketpair(PF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, resolve->fds+2); |
8a6233fb TG |
445 | if (r < 0) |
446 | goto fail; | |
e963e3ad | 447 | |
3bedba4a TG |
448 | for (resolve->valid_workers = 0; resolve->valid_workers < n_proc; resolve->valid_workers++) { |
449 | r = pthread_create(&resolve->workers[resolve->valid_workers], NULL, thread_worker, resolve); | |
8e50b5a7 | 450 | if (r) { |
e963e3ad DB |
451 | errno = r; |
452 | goto fail; | |
453 | } | |
454 | } | |
455 | ||
3bedba4a TG |
456 | resolve->current_index = resolve->current_id = 0; |
457 | resolve->done_head = resolve->done_tail = NULL; | |
458 | resolve->n_queries = 0; | |
e963e3ad | 459 | |
3bedba4a | 460 | fd_nonblock(resolve->fds[RESPONSE_RECV_FD], true); |
e963e3ad | 461 | |
3bedba4a | 462 | return resolve; |
e963e3ad DB |
463 | |
464 | fail: | |
3bedba4a TG |
465 | if (resolve) |
466 | sd_resolve_free(resolve); | |
e963e3ad DB |
467 | |
468 | return NULL; | |
469 | } | |
470 | ||
35bbea48 | 471 | _public_ void sd_resolve_free(sd_resolve *resolve) { |
e963e3ad DB |
472 | int i; |
473 | int saved_errno = errno; | |
474 | unsigned p; | |
475 | ||
3bedba4a | 476 | assert(resolve); |
e963e3ad | 477 | |
3bedba4a | 478 | resolve->dead = 1; |
e963e3ad | 479 | |
3bedba4a | 480 | if (resolve->fds[REQUEST_SEND_FD] >= 0) { |
5599e866 | 481 | RHeader req = {}; |
e963e3ad DB |
482 | |
483 | req.type = REQUEST_TERMINATE; | |
484 | req.length = sizeof(req); | |
485 | req.id = 0; | |
486 | ||
487 | /* Send one termination packet for each worker */ | |
3bedba4a TG |
488 | for (p = 0; p < resolve->valid_workers; p++) |
489 | send(resolve->fds[REQUEST_SEND_FD], &req, req.length, MSG_NOSIGNAL); | |
e963e3ad DB |
490 | } |
491 | ||
492 | /* Now terminate them and wait until they are gone. */ | |
3bedba4a | 493 | for (p = 0; p < resolve->valid_workers; p++) { |
e963e3ad | 494 | for (;;) { |
3bedba4a | 495 | if (pthread_join(resolve->workers[p], NULL) != EINTR) |
e963e3ad DB |
496 | break; |
497 | } | |
498 | } | |
499 | ||
500 | /* Close all communication channels */ | |
501 | for (i = 0; i < MESSAGE_FD_MAX; i++) | |
3bedba4a TG |
502 | if (resolve->fds[i] >= 0) |
503 | close(resolve->fds[i]); | |
e963e3ad DB |
504 | |
505 | for (p = 0; p < MAX_QUERIES; p++) | |
3bedba4a TG |
506 | if (resolve->queries[p]) |
507 | sd_resolve_cancel(resolve, resolve->queries[p]); | |
e963e3ad | 508 | |
3bedba4a | 509 | free(resolve); |
e963e3ad DB |
510 | |
511 | errno = saved_errno; | |
512 | } | |
513 | ||
35bbea48 | 514 | _public_ int sd_resolve_fd(sd_resolve *resolve) { |
3bedba4a | 515 | assert(resolve); |
e963e3ad | 516 | |
3bedba4a | 517 | return resolve->fds[RESPONSE_RECV_FD]; |
e963e3ad DB |
518 | } |
519 | ||
4f809256 DB |
520 | static sd_resolve_query *lookup_query(sd_resolve *resolve, unsigned id) { |
521 | sd_resolve_query *q; | |
3bedba4a | 522 | assert(resolve); |
e963e3ad | 523 | |
3bedba4a | 524 | q = resolve->queries[id % MAX_QUERIES]; |
8e50b5a7 | 525 | if (q) |
e963e3ad DB |
526 | if (q->id == id) |
527 | return q; | |
528 | ||
529 | return NULL; | |
530 | } | |
531 | ||
4f809256 | 532 | static void complete_query(sd_resolve *resolve, sd_resolve_query *q) { |
3bedba4a | 533 | assert(resolve); |
e963e3ad DB |
534 | assert(q); |
535 | assert(!q->done); | |
536 | ||
537 | q->done = 1; | |
538 | ||
3bedba4a TG |
539 | if ((q->done_prev = resolve->done_tail)) |
540 | resolve->done_tail->done_next = q; | |
e963e3ad | 541 | else |
3bedba4a | 542 | resolve->done_head = q; |
e963e3ad | 543 | |
3bedba4a | 544 | resolve->done_tail = q; |
e963e3ad DB |
545 | q->done_next = NULL; |
546 | } | |
547 | ||
548 | static const void *unserialize_addrinfo(const void *p, struct addrinfo **ret_ai, size_t *length) { | |
5599e866 | 549 | AddrInfoSerialization s; |
e963e3ad DB |
550 | size_t l; |
551 | struct addrinfo *ai; | |
552 | assert(p); | |
553 | assert(ret_ai); | |
554 | assert(length); | |
555 | ||
5599e866 | 556 | if (*length < sizeof(AddrInfoSerialization)) |
e963e3ad DB |
557 | return NULL; |
558 | ||
559 | memcpy(&s, p, sizeof(s)); | |
560 | ||
5599e866 | 561 | l = sizeof(AddrInfoSerialization) + s.ai_addrlen + s.canonname_len; |
e963e3ad DB |
562 | if (*length < l) |
563 | return NULL; | |
564 | ||
885d1c80 | 565 | ai = new(struct addrinfo, 1); |
8e50b5a7 | 566 | if (!ai) |
e963e3ad DB |
567 | goto fail; |
568 | ||
569 | ai->ai_addr = NULL; | |
570 | ai->ai_canonname = NULL; | |
571 | ai->ai_next = NULL; | |
572 | ||
573 | if (s.ai_addrlen && !(ai->ai_addr = malloc(s.ai_addrlen))) | |
574 | goto fail; | |
575 | ||
576 | if (s.canonname_len && !(ai->ai_canonname = malloc(s.canonname_len))) | |
577 | goto fail; | |
578 | ||
579 | ai->ai_flags = s.ai_flags; | |
580 | ai->ai_family = s.ai_family; | |
581 | ai->ai_socktype = s.ai_socktype; | |
582 | ai->ai_protocol = s.ai_protocol; | |
583 | ai->ai_addrlen = s.ai_addrlen; | |
584 | ||
585 | if (ai->ai_addr) | |
5599e866 | 586 | memcpy(ai->ai_addr, (const uint8_t*) p + sizeof(AddrInfoSerialization), s.ai_addrlen); |
e963e3ad DB |
587 | |
588 | if (ai->ai_canonname) | |
5599e866 | 589 | memcpy(ai->ai_canonname, (const uint8_t*) p + sizeof(AddrInfoSerialization) + s.ai_addrlen, s.canonname_len); |
e963e3ad DB |
590 | |
591 | *length -= l; | |
592 | *ret_ai = ai; | |
593 | ||
594 | return (const uint8_t*) p + l; | |
595 | ||
596 | ||
597 | fail: | |
598 | if (ai) | |
3bedba4a | 599 | sd_resolve_freeaddrinfo(ai); |
e963e3ad DB |
600 | |
601 | return NULL; | |
602 | } | |
603 | ||
5599e866 DB |
604 | static int handle_response(sd_resolve *resolve, const Packet *packet, size_t length) { |
605 | const RHeader *resp; | |
4f809256 | 606 | sd_resolve_query *q; |
e963e3ad | 607 | |
3bedba4a | 608 | assert(resolve); |
e963e3ad DB |
609 | |
610 | resp = &packet->rheader; | |
611 | assert(resp); | |
5599e866 | 612 | assert(length >= sizeof(RHeader)); |
e963e3ad DB |
613 | assert(length == resp->length); |
614 | ||
615 | if (resp->type == RESPONSE_DIED) { | |
3bedba4a | 616 | resolve->dead = 1; |
e963e3ad DB |
617 | return 0; |
618 | } | |
619 | ||
3bedba4a | 620 | q = lookup_query(resolve, resp->id); |
8e50b5a7 | 621 | if (!q) |
e963e3ad DB |
622 | return 0; |
623 | ||
624 | switch (resp->type) { | |
625 | case RESPONSE_ADDRINFO: { | |
5599e866 | 626 | const AddrInfoResponse *ai_resp = &packet->addrinfo_response; |
e963e3ad DB |
627 | const void *p; |
628 | size_t l; | |
629 | struct addrinfo *prev = NULL; | |
630 | ||
5599e866 | 631 | assert(length >= sizeof(AddrInfoResponse)); |
e963e3ad DB |
632 | assert(q->type == REQUEST_ADDRINFO); |
633 | ||
634 | q->ret = ai_resp->ret; | |
635 | q->_errno = ai_resp->_errno; | |
636 | q->_h_errno = ai_resp->_h_errno; | |
5599e866 DB |
637 | l = length - sizeof(AddrInfoResponse); |
638 | p = (const uint8_t*) resp + sizeof(AddrInfoResponse); | |
e963e3ad DB |
639 | |
640 | while (l > 0 && p) { | |
641 | struct addrinfo *ai = NULL; | |
642 | p = unserialize_addrinfo(p, &ai, &l); | |
643 | ||
644 | if (!p || !ai) { | |
645 | q->ret = EAI_MEMORY; | |
646 | break; | |
647 | } | |
648 | ||
649 | if (prev) | |
650 | prev->ai_next = ai; | |
651 | else | |
652 | q->addrinfo = ai; | |
653 | ||
654 | prev = ai; | |
655 | } | |
656 | ||
3bedba4a | 657 | complete_query(resolve, q); |
e963e3ad DB |
658 | break; |
659 | } | |
660 | ||
661 | case RESPONSE_NAMEINFO: { | |
5599e866 | 662 | const NameInfoResponse *ni_resp = &packet->nameinfo_response; |
e963e3ad | 663 | |
5599e866 | 664 | assert(length >= sizeof(NameInfoResponse)); |
e963e3ad DB |
665 | assert(q->type == REQUEST_NAMEINFO); |
666 | ||
667 | q->ret = ni_resp->ret; | |
668 | q->_errno = ni_resp->_errno; | |
669 | q->_h_errno = ni_resp->_h_errno; | |
670 | ||
671 | if (ni_resp->hostlen) | |
5599e866 | 672 | if (!(q->host = strndup((const char*) ni_resp + sizeof(NameInfoResponse), ni_resp->hostlen-1))) |
e963e3ad DB |
673 | q->ret = EAI_MEMORY; |
674 | ||
675 | if (ni_resp->servlen) | |
5599e866 | 676 | if (!(q->serv = strndup((const char*) ni_resp + sizeof(NameInfoResponse) + ni_resp->hostlen, ni_resp->servlen-1))) |
e963e3ad DB |
677 | q->ret = EAI_MEMORY; |
678 | ||
3bedba4a | 679 | complete_query(resolve, q); |
e963e3ad DB |
680 | break; |
681 | } | |
682 | ||
683 | case RESPONSE_RES: { | |
5599e866 | 684 | const ResResponse *res_resp = &packet->res_response; |
e963e3ad | 685 | |
5599e866 | 686 | assert(length >= sizeof(ResResponse)); |
e963e3ad DB |
687 | assert(q->type == REQUEST_RES_QUERY || q->type == REQUEST_RES_SEARCH); |
688 | ||
689 | q->ret = res_resp->ret; | |
690 | q->_errno = res_resp->_errno; | |
691 | q->_h_errno = res_resp->_h_errno; | |
692 | ||
693 | if (res_resp->ret >= 0) { | |
694 | if (!(q->serv = malloc(res_resp->ret))) { | |
695 | q->ret = -1; | |
696 | q->_errno = ENOMEM; | |
697 | } else | |
5599e866 | 698 | memcpy(q->serv, (const char *)resp + sizeof(ResResponse), res_resp->ret); |
e963e3ad DB |
699 | } |
700 | ||
3bedba4a | 701 | complete_query(resolve, q); |
e963e3ad DB |
702 | break; |
703 | } | |
704 | ||
705 | default: | |
706 | ; | |
707 | } | |
708 | ||
709 | return 0; | |
710 | } | |
711 | ||
35bbea48 | 712 | _public_ int sd_resolve_wait(sd_resolve *resolve, int block) { |
e963e3ad | 713 | int handled = 0; |
3bedba4a | 714 | assert(resolve); |
e963e3ad DB |
715 | |
716 | for (;;) { | |
5599e866 | 717 | Packet buf[BUFSIZE/sizeof(Packet) + 1]; |
e963e3ad DB |
718 | ssize_t l; |
719 | ||
3bedba4a | 720 | if (resolve->dead) { |
e963e3ad DB |
721 | errno = ECHILD; |
722 | return -1; | |
723 | } | |
724 | ||
3bedba4a | 725 | l = recv(resolve->fds[RESPONSE_RECV_FD], buf, sizeof(buf), 0); |
8e50b5a7 | 726 | if (l < 0) { |
e963e3ad DB |
727 | fd_set fds; |
728 | ||
729 | if (errno != EAGAIN) | |
730 | return -1; | |
731 | ||
732 | if (!block || handled) | |
733 | return 0; | |
734 | ||
735 | FD_ZERO(&fds); | |
3bedba4a | 736 | FD_SET(resolve->fds[RESPONSE_RECV_FD], &fds); |
e963e3ad | 737 | |
3bedba4a | 738 | if (select(resolve->fds[RESPONSE_RECV_FD]+1, &fds, NULL, NULL, NULL) < 0) |
e963e3ad DB |
739 | return -1; |
740 | ||
741 | continue; | |
742 | } | |
743 | ||
3bedba4a | 744 | if (handle_response(resolve, buf, (size_t) l) < 0) |
e963e3ad DB |
745 | return -1; |
746 | ||
747 | handled = 1; | |
748 | } | |
749 | } | |
750 | ||
4f809256 DB |
751 | static sd_resolve_query *alloc_query(sd_resolve *resolve) { |
752 | sd_resolve_query *q; | |
3bedba4a | 753 | assert(resolve); |
e963e3ad | 754 | |
3bedba4a | 755 | if (resolve->n_queries >= MAX_QUERIES) { |
e963e3ad DB |
756 | errno = ENOMEM; |
757 | return NULL; | |
758 | } | |
759 | ||
3bedba4a TG |
760 | while (resolve->queries[resolve->current_index]) { |
761 | resolve->current_index++; | |
762 | resolve->current_id++; | |
e963e3ad | 763 | |
3bedba4a TG |
764 | while (resolve->current_index >= MAX_QUERIES) |
765 | resolve->current_index -= MAX_QUERIES; | |
e963e3ad DB |
766 | } |
767 | ||
885d1c80 | 768 | q = resolve->queries[resolve->current_index] = new(sd_resolve_query, 1); |
8e50b5a7 | 769 | if (!q) { |
e963e3ad DB |
770 | errno = ENOMEM; |
771 | return NULL; | |
772 | } | |
773 | ||
3bedba4a | 774 | resolve->n_queries++; |
e963e3ad | 775 | |
3bedba4a | 776 | q->resolve = resolve; |
e963e3ad | 777 | q->done = 0; |
3bedba4a | 778 | q->id = resolve->current_id; |
e963e3ad DB |
779 | q->done_next = q->done_prev = NULL; |
780 | q->ret = 0; | |
781 | q->_errno = 0; | |
782 | q->_h_errno = 0; | |
783 | q->addrinfo = NULL; | |
784 | q->userdata = NULL; | |
785 | q->host = q->serv = NULL; | |
786 | ||
787 | return q; | |
788 | } | |
789 | ||
35bbea48 | 790 | _public_ sd_resolve_query* sd_resolve_getaddrinfo(sd_resolve *resolve, const char *node, const char *service, const struct addrinfo *hints) { |
5599e866 DB |
791 | AddrInfoRequest data[BUFSIZE/sizeof(AddrInfoRequest) + 1] = {}; |
792 | AddrInfoRequest *req = data; | |
4f809256 | 793 | sd_resolve_query *q; |
3bedba4a | 794 | assert(resolve); |
e963e3ad DB |
795 | assert(node || service); |
796 | ||
3bedba4a | 797 | if (resolve->dead) { |
e963e3ad DB |
798 | errno = ECHILD; |
799 | return NULL; | |
800 | } | |
801 | ||
3bedba4a | 802 | q = alloc_query(resolve); |
8e50b5a7 | 803 | if (!q) |
e963e3ad DB |
804 | return NULL; |
805 | ||
e963e3ad DB |
806 | req->node_len = node ? strlen(node)+1 : 0; |
807 | req->service_len = service ? strlen(service)+1 : 0; | |
808 | ||
809 | req->header.id = q->id; | |
810 | req->header.type = q->type = REQUEST_ADDRINFO; | |
5599e866 | 811 | req->header.length = sizeof(AddrInfoRequest) + req->node_len + req->service_len; |
e963e3ad DB |
812 | |
813 | if (req->header.length > BUFSIZE) { | |
814 | errno = ENOMEM; | |
815 | goto fail; | |
816 | } | |
817 | ||
818 | if (!(req->hints_is_null = !hints)) { | |
819 | req->ai_flags = hints->ai_flags; | |
820 | req->ai_family = hints->ai_family; | |
821 | req->ai_socktype = hints->ai_socktype; | |
822 | req->ai_protocol = hints->ai_protocol; | |
823 | } | |
824 | ||
825 | if (node) | |
5599e866 | 826 | strcpy((char*) req + sizeof(AddrInfoRequest), node); |
e963e3ad DB |
827 | |
828 | if (service) | |
5599e866 | 829 | strcpy((char*) req + sizeof(AddrInfoRequest) + req->node_len, service); |
e963e3ad | 830 | |
3bedba4a | 831 | if (send(resolve->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0) |
e963e3ad DB |
832 | goto fail; |
833 | ||
834 | return q; | |
835 | ||
836 | fail: | |
837 | if (q) | |
3bedba4a | 838 | sd_resolve_cancel(resolve, q); |
e963e3ad DB |
839 | |
840 | return NULL; | |
841 | } | |
842 | ||
35bbea48 | 843 | _public_ int sd_resolve_getaddrinfo_done(sd_resolve *resolve, sd_resolve_query* q, struct addrinfo **ret_res) { |
e963e3ad | 844 | int ret; |
3bedba4a | 845 | assert(resolve); |
e963e3ad | 846 | assert(q); |
3bedba4a | 847 | assert(q->resolve == resolve); |
e963e3ad DB |
848 | assert(q->type == REQUEST_ADDRINFO); |
849 | ||
3bedba4a | 850 | if (resolve->dead) { |
e963e3ad DB |
851 | errno = ECHILD; |
852 | return EAI_SYSTEM; | |
853 | } | |
854 | ||
855 | if (!q->done) | |
856 | return EAI_AGAIN; | |
857 | ||
858 | *ret_res = q->addrinfo; | |
859 | q->addrinfo = NULL; | |
860 | ||
861 | ret = q->ret; | |
862 | ||
863 | if (ret == EAI_SYSTEM) | |
864 | errno = q->_errno; | |
865 | ||
866 | if (ret != 0) | |
867 | h_errno = q->_h_errno; | |
868 | ||
3bedba4a | 869 | sd_resolve_cancel(resolve, q); |
e963e3ad DB |
870 | |
871 | return ret; | |
872 | } | |
873 | ||
35bbea48 | 874 | _public_ sd_resolve_query* sd_resolve_getnameinfo(sd_resolve *resolve, const struct sockaddr *sa, socklen_t salen, int flags, int gethost, int getserv) { |
5599e866 DB |
875 | NameInfoRequest data[BUFSIZE/sizeof(NameInfoRequest) + 1] = {}; |
876 | NameInfoRequest *req = data; | |
4f809256 | 877 | sd_resolve_query *q; |
e963e3ad | 878 | |
3bedba4a | 879 | assert(resolve); |
e963e3ad DB |
880 | assert(sa); |
881 | assert(salen > 0); | |
882 | ||
3bedba4a | 883 | if (resolve->dead) { |
e963e3ad DB |
884 | errno = ECHILD; |
885 | return NULL; | |
886 | } | |
887 | ||
3bedba4a | 888 | q = alloc_query(resolve); |
8e50b5a7 | 889 | if (!q) |
e963e3ad DB |
890 | return NULL; |
891 | ||
e963e3ad DB |
892 | req->header.id = q->id; |
893 | req->header.type = q->type = REQUEST_NAMEINFO; | |
5599e866 | 894 | req->header.length = sizeof(NameInfoRequest) + salen; |
e963e3ad DB |
895 | |
896 | if (req->header.length > BUFSIZE) { | |
897 | errno = ENOMEM; | |
898 | goto fail; | |
899 | } | |
900 | ||
901 | req->flags = flags; | |
902 | req->sockaddr_len = salen; | |
903 | req->gethost = gethost; | |
904 | req->getserv = getserv; | |
905 | ||
5599e866 | 906 | memcpy((uint8_t*) req + sizeof(NameInfoRequest), sa, salen); |
e963e3ad | 907 | |
3bedba4a | 908 | if (send(resolve->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0) |
e963e3ad DB |
909 | goto fail; |
910 | ||
911 | return q; | |
912 | ||
913 | fail: | |
914 | if (q) | |
3bedba4a | 915 | sd_resolve_cancel(resolve, q); |
e963e3ad DB |
916 | |
917 | return NULL; | |
918 | } | |
919 | ||
35bbea48 | 920 | _public_ int sd_resolve_getnameinfo_done(sd_resolve *resolve, sd_resolve_query* q, char *ret_host, size_t hostlen, char *ret_serv, size_t servlen) { |
e963e3ad | 921 | int ret; |
3bedba4a | 922 | assert(resolve); |
e963e3ad | 923 | assert(q); |
3bedba4a | 924 | assert(q->resolve == resolve); |
e963e3ad DB |
925 | assert(q->type == REQUEST_NAMEINFO); |
926 | assert(!ret_host || hostlen); | |
927 | assert(!ret_serv || servlen); | |
928 | ||
3bedba4a | 929 | if (resolve->dead) { |
e963e3ad DB |
930 | errno = ECHILD; |
931 | return EAI_SYSTEM; | |
932 | } | |
933 | ||
934 | if (!q->done) | |
935 | return EAI_AGAIN; | |
936 | ||
937 | if (ret_host && q->host) { | |
938 | strncpy(ret_host, q->host, hostlen); | |
939 | ret_host[hostlen-1] = 0; | |
940 | } | |
941 | ||
942 | if (ret_serv && q->serv) { | |
943 | strncpy(ret_serv, q->serv, servlen); | |
944 | ret_serv[servlen-1] = 0; | |
945 | } | |
946 | ||
947 | ret = q->ret; | |
948 | ||
949 | if (ret == EAI_SYSTEM) | |
950 | errno = q->_errno; | |
951 | ||
952 | if (ret != 0) | |
953 | h_errno = q->_h_errno; | |
954 | ||
3bedba4a | 955 | sd_resolve_cancel(resolve, q); |
e963e3ad DB |
956 | |
957 | return ret; | |
958 | } | |
959 | ||
5599e866 DB |
960 | static sd_resolve_query * resolve_res(sd_resolve *resolve, QueryType qtype, const char *dname, int class, int type) { |
961 | ResRequest data[BUFSIZE/sizeof(ResRequest) + 1]; | |
962 | ResRequest *req = data; | |
4f809256 | 963 | sd_resolve_query *q; |
e963e3ad | 964 | |
3bedba4a | 965 | assert(resolve); |
e963e3ad DB |
966 | assert(dname); |
967 | ||
3bedba4a | 968 | if (resolve->dead) { |
e963e3ad DB |
969 | errno = ECHILD; |
970 | return NULL; | |
971 | } | |
972 | ||
3bedba4a | 973 | q = alloc_query(resolve); |
8e50b5a7 | 974 | if (!q) |
e963e3ad DB |
975 | return NULL; |
976 | ||
977 | req->dname_len = strlen(dname) + 1; | |
978 | ||
979 | req->header.id = q->id; | |
980 | req->header.type = q->type = qtype; | |
5599e866 | 981 | req->header.length = sizeof(ResRequest) + req->dname_len; |
e963e3ad DB |
982 | |
983 | if (req->header.length > BUFSIZE) { | |
984 | errno = ENOMEM; | |
985 | goto fail; | |
986 | } | |
987 | ||
988 | req->class = class; | |
989 | req->type = type; | |
990 | ||
5599e866 | 991 | strcpy((char*) req + sizeof(ResRequest), dname); |
e963e3ad | 992 | |
3bedba4a | 993 | if (send(resolve->fds[REQUEST_SEND_FD], req, req->header.length, MSG_NOSIGNAL) < 0) |
e963e3ad DB |
994 | goto fail; |
995 | ||
996 | return q; | |
997 | ||
998 | fail: | |
999 | if (q) | |
3bedba4a | 1000 | sd_resolve_cancel(resolve, q); |
e963e3ad DB |
1001 | |
1002 | return NULL; | |
1003 | } | |
1004 | ||
35bbea48 | 1005 | _public_ sd_resolve_query* sd_resolve_res_query(sd_resolve *resolve, const char *dname, int class, int type) { |
3bedba4a | 1006 | return resolve_res(resolve, REQUEST_RES_QUERY, dname, class, type); |
e963e3ad DB |
1007 | } |
1008 | ||
35bbea48 | 1009 | _public_ sd_resolve_query* sd_resolve_res_search(sd_resolve *resolve, const char *dname, int class, int type) { |
3bedba4a | 1010 | return resolve_res(resolve, REQUEST_RES_SEARCH, dname, class, type); |
e963e3ad DB |
1011 | } |
1012 | ||
35bbea48 | 1013 | _public_ int sd_resolve_res_done(sd_resolve *resolve, sd_resolve_query* q, unsigned char **answer) { |
e963e3ad | 1014 | int ret; |
3bedba4a | 1015 | assert(resolve); |
e963e3ad | 1016 | assert(q); |
3bedba4a | 1017 | assert(q->resolve == resolve); |
e963e3ad DB |
1018 | assert(q->type == REQUEST_RES_QUERY || q->type == REQUEST_RES_SEARCH); |
1019 | assert(answer); | |
1020 | ||
3bedba4a | 1021 | if (resolve->dead) { |
e963e3ad DB |
1022 | errno = ECHILD; |
1023 | return -ECHILD; | |
1024 | } | |
1025 | ||
1026 | if (!q->done) { | |
1027 | errno = EAGAIN; | |
1028 | return -EAGAIN; | |
1029 | } | |
1030 | ||
1031 | *answer = (unsigned char *)q->serv; | |
1032 | q->serv = NULL; | |
1033 | ||
1034 | ret = q->ret; | |
1035 | ||
1036 | if (ret < 0) { | |
1037 | errno = q->_errno; | |
1038 | h_errno = q->_h_errno; | |
1039 | } | |
1040 | ||
3bedba4a | 1041 | sd_resolve_cancel(resolve, q); |
e963e3ad DB |
1042 | |
1043 | return ret < 0 ? -errno : ret; | |
1044 | } | |
1045 | ||
35bbea48 | 1046 | _public_ sd_resolve_query* sd_resolve_get_next(sd_resolve *resolve) { |
3bedba4a TG |
1047 | assert(resolve); |
1048 | return resolve->done_head; | |
e963e3ad DB |
1049 | } |
1050 | ||
35bbea48 | 1051 | _public_ int sd_resolve_get_n_queries(sd_resolve *resolve) { |
3bedba4a TG |
1052 | assert(resolve); |
1053 | return resolve->n_queries; | |
e963e3ad DB |
1054 | } |
1055 | ||
35bbea48 | 1056 | _public_ void sd_resolve_cancel(sd_resolve *resolve, sd_resolve_query* q) { |
e963e3ad DB |
1057 | int i; |
1058 | int saved_errno = errno; | |
1059 | ||
3bedba4a | 1060 | assert(resolve); |
e963e3ad | 1061 | assert(q); |
3bedba4a TG |
1062 | assert(q->resolve == resolve); |
1063 | assert(resolve->n_queries > 0); | |
e963e3ad DB |
1064 | |
1065 | if (q->done) { | |
1066 | ||
1067 | if (q->done_prev) | |
1068 | q->done_prev->done_next = q->done_next; | |
1069 | else | |
3bedba4a | 1070 | resolve->done_head = q->done_next; |
e963e3ad DB |
1071 | |
1072 | if (q->done_next) | |
1073 | q->done_next->done_prev = q->done_prev; | |
1074 | else | |
3bedba4a | 1075 | resolve->done_tail = q->done_prev; |
e963e3ad DB |
1076 | } |
1077 | ||
1078 | i = q->id % MAX_QUERIES; | |
3bedba4a TG |
1079 | assert(resolve->queries[i] == q); |
1080 | resolve->queries[i] = NULL; | |
e963e3ad | 1081 | |
3bedba4a | 1082 | sd_resolve_freeaddrinfo(q->addrinfo); |
e963e3ad DB |
1083 | free(q->host); |
1084 | free(q->serv); | |
1085 | ||
3bedba4a | 1086 | resolve->n_queries--; |
e963e3ad DB |
1087 | free(q); |
1088 | ||
1089 | errno = saved_errno; | |
1090 | } | |
1091 | ||
35bbea48 | 1092 | _public_ void sd_resolve_freeaddrinfo(struct addrinfo *ai) { |
e963e3ad DB |
1093 | int saved_errno = errno; |
1094 | ||
1095 | while (ai) { | |
1096 | struct addrinfo *next = ai->ai_next; | |
1097 | ||
1098 | free(ai->ai_addr); | |
1099 | free(ai->ai_canonname); | |
1100 | free(ai); | |
1101 | ||
1102 | ai = next; | |
1103 | } | |
1104 | ||
1105 | errno = saved_errno; | |
1106 | } | |
1107 | ||
35bbea48 | 1108 | _public_ int sd_resolve_isdone(sd_resolve *resolve, sd_resolve_query*q) { |
3bedba4a | 1109 | assert(resolve); |
e963e3ad | 1110 | assert(q); |
3bedba4a | 1111 | assert(q->resolve == resolve); |
e963e3ad DB |
1112 | |
1113 | return q->done; | |
1114 | } | |
1115 | ||
35bbea48 | 1116 | _public_ void sd_resolve_setuserdata(sd_resolve *resolve, sd_resolve_query *q, void *userdata) { |
e963e3ad | 1117 | assert(q); |
3bedba4a TG |
1118 | assert(resolve); |
1119 | assert(q->resolve = resolve); | |
e963e3ad DB |
1120 | |
1121 | q->userdata = userdata; | |
1122 | } | |
1123 | ||
35bbea48 | 1124 | _public_ void* sd_resolve_getuserdata(sd_resolve *resolve, sd_resolve_query *q) { |
e963e3ad | 1125 | assert(q); |
3bedba4a TG |
1126 | assert(resolve); |
1127 | assert(q->resolve = resolve); | |
e963e3ad DB |
1128 | |
1129 | return q->userdata; | |
1130 | } |