1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2005-2008 Lennart Poettering
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.
13 systemd is distributed in the hope that it will be useful, but
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.
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/>.
31 #include <sys/prctl.h>
36 #include "socket-util.h"
38 #include "resolve-util.h"
39 #include "sd-resolve.h"
41 #define WORKERS_MIN 1U
42 #define WORKERS_MAX 16U
43 #define QUERIES_MAX 256U
44 #define BUFSIZE 10240U
74 pthread_t workers[WORKERS_MAX];
75 unsigned n_valid_workers;
78 sd_resolve_query* query_array[QUERIES_MAX];
79 unsigned n_queries, n_done, n_outstanding;
81 sd_event_source *event_source;
84 sd_resolve_query *current;
86 sd_resolve **default_resolve_ptr;
89 LIST_HEAD(sd_resolve_query, queries);
92 struct sd_resolve_query {
105 struct addrinfo *addrinfo;
107 unsigned char *answer;
110 sd_resolve_getaddrinfo_handler_t getaddrinfo_handler;
111 sd_resolve_getnameinfo_handler_t getnameinfo_handler;
112 sd_resolve_res_handler_t res_handler;
117 LIST_FIELDS(sd_resolve_query, queries);
120 typedef struct RHeader {
126 typedef struct AddrInfoRequest {
127 struct RHeader header;
133 size_t node_len, service_len;
136 typedef struct AddrInfoResponse {
137 struct RHeader header;
141 /* followed by addrinfo_serialization[] */
144 typedef struct AddrInfoSerialization {
150 size_t canonname_len;
151 /* Followed by ai_addr amd ai_canonname with variable lengths */
152 } AddrInfoSerialization;
154 typedef struct NameInfoRequest {
155 struct RHeader header;
157 socklen_t sockaddr_len;
158 bool gethost:1, getserv:1;
161 typedef struct NameInfoResponse {
162 struct RHeader header;
163 size_t hostlen, servlen;
169 typedef struct ResRequest {
170 struct RHeader header;
176 typedef struct ResResponse {
177 struct RHeader header;
183 typedef union Packet {
185 AddrInfoRequest addrinfo_request;
186 AddrInfoResponse addrinfo_response;
187 NameInfoRequest nameinfo_request;
188 NameInfoResponse nameinfo_response;
189 ResRequest res_request;
190 ResResponse res_response;
193 static int getaddrinfo_done(sd_resolve_query* q);
194 static int getnameinfo_done(sd_resolve_query *q);
195 static int res_query_done(sd_resolve_query* q);
197 static void resolve_query_disconnect(sd_resolve_query *q);
199 #define RESOLVE_DONT_DESTROY(resolve) \
200 _cleanup_resolve_unref_ _unused_ sd_resolve *_dont_destroy_##resolve = sd_resolve_ref(resolve)
202 static int send_died(int out_fd) {
205 .type = RESPONSE_DIED,
206 .length = sizeof(RHeader),
211 if (send(out_fd, &rh, rh.length, MSG_NOSIGNAL) < 0)
217 static void *serialize_addrinfo(void *p, const struct addrinfo *ai, size_t *length, size_t maxlength) {
218 AddrInfoSerialization s;
224 assert(*length <= maxlength);
226 cnl = ai->ai_canonname ? strlen(ai->ai_canonname)+1 : 0;
227 l = sizeof(AddrInfoSerialization) + ai->ai_addrlen + cnl;
229 if (*length + l > maxlength)
232 s.ai_flags = ai->ai_flags;
233 s.ai_family = ai->ai_family;
234 s.ai_socktype = ai->ai_socktype;
235 s.ai_protocol = ai->ai_protocol;
236 s.ai_addrlen = ai->ai_addrlen;
237 s.canonname_len = cnl;
239 memcpy((uint8_t*) p, &s, sizeof(AddrInfoSerialization));
240 memcpy((uint8_t*) p + sizeof(AddrInfoSerialization), ai->ai_addr, ai->ai_addrlen);
242 if (ai->ai_canonname)
243 memcpy((char*) p + sizeof(AddrInfoSerialization) + ai->ai_addrlen, ai->ai_canonname, cnl);
246 return (uint8_t*) p + l;
249 static int send_addrinfo_reply(
257 AddrInfoResponse resp = {
258 .header.type = RESPONSE_ADDRINFO,
260 .header.length = sizeof(AddrInfoResponse),
263 ._h_errno = _h_errno,
266 struct msghdr mh = {};
269 AddrInfoSerialization ais;
270 uint8_t space[BUFSIZE];
275 if (ret == 0 && ai) {
279 for (k = ai; k; k = k->ai_next) {
280 p = serialize_addrinfo(p, k, &resp.header.length, (uint8_t*) &buffer + BUFSIZE - (uint8_t*) p);
291 iov[0] = (struct iovec) { .iov_base = &resp, .iov_len = sizeof(AddrInfoResponse) };
292 iov[1] = (struct iovec) { .iov_base = &buffer, .iov_len = resp.header.length - sizeof(AddrInfoResponse) };
295 mh.msg_iovlen = ELEMENTSOF(iov);
297 if (sendmsg(out_fd, &mh, MSG_NOSIGNAL) < 0)
303 static int send_nameinfo_reply(
312 NameInfoResponse resp = {
313 .header.type = RESPONSE_NAMEINFO,
317 ._h_errno = _h_errno,
320 struct msghdr mh = {};
326 sl = serv ? strlen(serv)+1 : 0;
327 hl = host ? strlen(host)+1 : 0;
329 resp.header.length = sizeof(NameInfoResponse) + hl + sl;
333 iov[0] = (struct iovec) { .iov_base = &resp, .iov_len = sizeof(NameInfoResponse) };
334 iov[1] = (struct iovec) { .iov_base = (void*) host, .iov_len = hl };
335 iov[2] = (struct iovec) { .iov_base = (void*) serv, .iov_len = sl };
338 mh.msg_iovlen = ELEMENTSOF(iov);
340 if (sendmsg(out_fd, &mh, MSG_NOSIGNAL) < 0)
346 static int send_res_reply(int out_fd, unsigned id, const unsigned char *answer, int ret, int _errno, int _h_errno) {
349 .header.type = RESPONSE_RES,
353 ._h_errno = _h_errno,
356 struct msghdr mh = {};
362 l = ret > 0 ? (size_t) ret : 0;
364 resp.header.length = sizeof(ResResponse) + l;
366 iov[0] = (struct iovec) { .iov_base = &resp, .iov_len = sizeof(ResResponse) };
367 iov[1] = (struct iovec) { .iov_base = (void*) answer, .iov_len = l };
370 mh.msg_iovlen = ELEMENTSOF(iov);
372 if (sendmsg(out_fd, &mh, MSG_NOSIGNAL) < 0)
378 static int handle_request(int out_fd, const Packet *packet, size_t length) {
384 req = &packet->rheader;
386 assert(length >= sizeof(RHeader));
387 assert(length == req->length);
391 case REQUEST_ADDRINFO: {
392 const AddrInfoRequest *ai_req = &packet->addrinfo_request;
393 struct addrinfo hints = {}, *result = NULL;
394 const char *node, *service;
397 assert(length >= sizeof(AddrInfoRequest));
398 assert(length == sizeof(AddrInfoRequest) + ai_req->node_len + ai_req->service_len);
400 hints.ai_flags = ai_req->ai_flags;
401 hints.ai_family = ai_req->ai_family;
402 hints.ai_socktype = ai_req->ai_socktype;
403 hints.ai_protocol = ai_req->ai_protocol;
405 node = ai_req->node_len ? (const char*) ai_req + sizeof(AddrInfoRequest) : NULL;
406 service = ai_req->service_len ? (const char*) ai_req + sizeof(AddrInfoRequest) + ai_req->node_len : NULL;
410 ai_req->hints_valid ? &hints : NULL,
413 /* send_addrinfo_reply() frees result */
414 return send_addrinfo_reply(out_fd, req->id, ret, result, errno, h_errno);
417 case REQUEST_NAMEINFO: {
418 const NameInfoRequest *ni_req = &packet->nameinfo_request;
419 char hostbuf[NI_MAXHOST], servbuf[NI_MAXSERV];
420 union sockaddr_union sa;
423 assert(length >= sizeof(NameInfoRequest));
424 assert(length == sizeof(NameInfoRequest) + ni_req->sockaddr_len);
425 assert(sizeof(sa) >= ni_req->sockaddr_len);
427 memcpy(&sa, (const uint8_t *) ni_req + sizeof(NameInfoRequest), ni_req->sockaddr_len);
429 ret = getnameinfo(&sa.sa, ni_req->sockaddr_len,
430 ni_req->gethost ? hostbuf : NULL, ni_req->gethost ? sizeof(hostbuf) : 0,
431 ni_req->getserv ? servbuf : NULL, ni_req->getserv ? sizeof(servbuf) : 0,
434 return send_nameinfo_reply(out_fd, req->id, ret,
435 ret == 0 && ni_req->gethost ? hostbuf : NULL,
436 ret == 0 && ni_req->getserv ? servbuf : NULL,
440 case REQUEST_RES_QUERY:
441 case REQUEST_RES_SEARCH: {
442 const ResRequest *res_req = &packet->res_request;
445 uint8_t space[BUFSIZE];
450 assert(length >= sizeof(ResRequest));
451 assert(length == sizeof(ResRequest) + res_req->dname_len);
453 dname = (const char *) res_req + sizeof(ResRequest);
455 if (req->type == REQUEST_RES_QUERY)
456 ret = res_query(dname, res_req->class, res_req->type, (unsigned char *) &answer, BUFSIZE);
458 ret = res_search(dname, res_req->class, res_req->type, (unsigned char *) &answer, BUFSIZE);
460 return send_res_reply(out_fd, req->id, (unsigned char *) &answer, ret, errno, h_errno);
463 case REQUEST_TERMINATE:
468 assert_not_reached("Unknown request");
474 static void* thread_worker(void *p) {
475 sd_resolve *resolve = p;
478 /* No signals in this thread please */
479 assert_se(sigfillset(&fullset) == 0);
480 assert_se(pthread_sigmask(SIG_BLOCK, &fullset, NULL) == 0);
482 /* Assign a pretty name to this thread */
483 prctl(PR_SET_NAME, (unsigned long) "sd-resolve");
485 while (!resolve->dead) {
488 uint8_t space[BUFSIZE];
492 length = recv(resolve->fds[REQUEST_RECV_FD], &buf, sizeof(buf), 0);
505 if (handle_request(resolve->fds[RESPONSE_SEND_FD], &buf.packet, (size_t) length) < 0)
509 send_died(resolve->fds[RESPONSE_SEND_FD]);
514 static int start_threads(sd_resolve *resolve, unsigned extra) {
518 n = resolve->n_outstanding + extra;
519 n = CLAMP(n, WORKERS_MIN, WORKERS_MAX);
521 while (resolve->n_valid_workers < n) {
523 r = pthread_create(&resolve->workers[resolve->n_valid_workers], NULL, thread_worker, resolve);
527 resolve->n_valid_workers ++;
533 static bool resolve_pid_changed(sd_resolve *r) {
536 /* We don't support people creating a resolver and keeping it
537 * around after fork(). Let's complain. */
539 return r->original_pid != getpid();
542 _public_ int sd_resolve_new(sd_resolve **ret) {
543 sd_resolve *resolve = NULL;
546 assert_return(ret, -EINVAL);
548 resolve = new0(sd_resolve, 1);
553 resolve->original_pid = getpid();
555 for (i = 0; i < _FD_MAX; i++)
556 resolve->fds[i] = -1;
558 r = socketpair(PF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, resolve->fds + REQUEST_RECV_FD);
564 r = socketpair(PF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, resolve->fds + RESPONSE_RECV_FD);
570 fd_inc_sndbuf(resolve->fds[REQUEST_SEND_FD], QUERIES_MAX * BUFSIZE);
571 fd_inc_rcvbuf(resolve->fds[REQUEST_RECV_FD], QUERIES_MAX * BUFSIZE);
572 fd_inc_sndbuf(resolve->fds[RESPONSE_SEND_FD], QUERIES_MAX * BUFSIZE);
573 fd_inc_rcvbuf(resolve->fds[RESPONSE_RECV_FD], QUERIES_MAX * BUFSIZE);
575 fd_nonblock(resolve->fds[RESPONSE_RECV_FD], true);
581 sd_resolve_unref(resolve);
585 _public_ int sd_resolve_default(sd_resolve **ret) {
587 static thread_local sd_resolve *default_resolve = NULL;
588 sd_resolve *e = NULL;
592 return !!default_resolve;
594 if (default_resolve) {
595 *ret = sd_resolve_ref(default_resolve);
599 r = sd_resolve_new(&e);
603 e->default_resolve_ptr = &default_resolve;
611 _public_ int sd_resolve_get_tid(sd_resolve *resolve, pid_t *tid) {
612 assert_return(resolve, -EINVAL);
613 assert_return(tid, -EINVAL);
614 assert_return(!resolve_pid_changed(resolve), -ECHILD);
616 if (resolve->tid != 0) {
622 return sd_event_get_tid(resolve->event, tid);
627 static void resolve_free(sd_resolve *resolve) {
634 while ((q = resolve->queries)) {
636 resolve_query_disconnect(q);
637 sd_resolve_query_unref(q);
640 if (resolve->default_resolve_ptr)
641 *(resolve->default_resolve_ptr) = NULL;
643 resolve->dead = true;
645 sd_resolve_detach_event(resolve);
647 if (resolve->fds[REQUEST_SEND_FD] >= 0) {
650 .type = REQUEST_TERMINATE,
651 .length = sizeof(req)
654 /* Send one termination packet for each worker */
655 for (i = 0; i < resolve->n_valid_workers; i++)
656 (void) send(resolve->fds[REQUEST_SEND_FD], &req, req.length, MSG_NOSIGNAL);
659 /* Now terminate them and wait until they are gone. */
660 for (i = 0; i < resolve->n_valid_workers; i++) {
662 if (pthread_join(resolve->workers[i], NULL) != EINTR)
667 /* Close all communication channels */
668 for (i = 0; i < _FD_MAX; i++)
669 safe_close(resolve->fds[i]);
674 _public_ sd_resolve* sd_resolve_ref(sd_resolve *resolve) {
675 assert_return(resolve, NULL);
677 assert(resolve->n_ref >= 1);
683 _public_ sd_resolve* sd_resolve_unref(sd_resolve *resolve) {
688 assert(resolve->n_ref >= 1);
691 if (resolve->n_ref <= 0)
692 resolve_free(resolve);
697 _public_ int sd_resolve_get_fd(sd_resolve *resolve) {
698 assert_return(resolve, -EINVAL);
699 assert_return(!resolve_pid_changed(resolve), -ECHILD);
701 return resolve->fds[RESPONSE_RECV_FD];
704 _public_ int sd_resolve_get_events(sd_resolve *resolve) {
705 assert_return(resolve, -EINVAL);
706 assert_return(!resolve_pid_changed(resolve), -ECHILD);
708 return resolve->n_queries > resolve->n_done ? POLLIN : 0;
711 _public_ int sd_resolve_get_timeout(sd_resolve *resolve, uint64_t *usec) {
712 assert_return(resolve, -EINVAL);
713 assert_return(usec, -EINVAL);
714 assert_return(!resolve_pid_changed(resolve), -ECHILD);
716 *usec = (uint64_t) -1;
720 static sd_resolve_query *lookup_query(sd_resolve *resolve, unsigned id) {
725 q = resolve->query_array[id % QUERIES_MAX];
733 static int complete_query(sd_resolve *resolve, sd_resolve_query *q) {
738 assert(q->resolve == resolve);
743 resolve->current = sd_resolve_query_ref(q);
747 case REQUEST_ADDRINFO:
748 r = getaddrinfo_done(q);
751 case REQUEST_NAMEINFO:
752 r = getnameinfo_done(q);
755 case REQUEST_RES_QUERY:
756 case REQUEST_RES_SEARCH:
757 r = res_query_done(q);
761 assert_not_reached("Cannot complete unknown query type");
764 resolve->current = NULL;
767 resolve_query_disconnect(q);
768 sd_resolve_query_unref(q);
771 sd_resolve_query_unref(q);
776 static int unserialize_addrinfo(const void **p, size_t *length, struct addrinfo **ret_ai) {
777 AddrInfoSerialization s;
786 if (*length < sizeof(AddrInfoSerialization))
789 memcpy(&s, *p, sizeof(s));
791 l = sizeof(AddrInfoSerialization) + s.ai_addrlen + s.canonname_len;
795 ai = new0(struct addrinfo, 1);
799 ai->ai_flags = s.ai_flags;
800 ai->ai_family = s.ai_family;
801 ai->ai_socktype = s.ai_socktype;
802 ai->ai_protocol = s.ai_protocol;
803 ai->ai_addrlen = s.ai_addrlen;
805 if (s.ai_addrlen > 0) {
806 ai->ai_addr = memdup((const uint8_t*) *p + sizeof(AddrInfoSerialization), s.ai_addrlen);
813 if (s.canonname_len > 0) {
814 ai->ai_canonname = memdup((const uint8_t*) *p + sizeof(AddrInfoSerialization) + s.ai_addrlen, s.canonname_len);
815 if (!ai->ai_canonname) {
824 *p = ((const uint8_t*) *p) + l;
829 static int handle_response(sd_resolve *resolve, const Packet *packet, size_t length) {
836 resp = &packet->rheader;
838 assert(length >= sizeof(RHeader));
839 assert(length == resp->length);
841 if (resp->type == RESPONSE_DIED) {
842 resolve->dead = true;
846 assert(resolve->n_outstanding > 0);
847 resolve->n_outstanding--;
849 q = lookup_query(resolve, resp->id);
853 switch (resp->type) {
855 case RESPONSE_ADDRINFO: {
856 const AddrInfoResponse *ai_resp = &packet->addrinfo_response;
859 struct addrinfo *prev = NULL;
861 assert(length >= sizeof(AddrInfoResponse));
862 assert(q->type == REQUEST_ADDRINFO);
864 q->ret = ai_resp->ret;
865 q->_errno = ai_resp->_errno;
866 q->_h_errno = ai_resp->_h_errno;
868 l = length - sizeof(AddrInfoResponse);
869 p = (const uint8_t*) resp + sizeof(AddrInfoResponse);
872 struct addrinfo *ai = NULL;
874 r = unserialize_addrinfo(&p, &l, &ai);
879 freeaddrinfo(q->addrinfo);
892 return complete_query(resolve, q);
895 case RESPONSE_NAMEINFO: {
896 const NameInfoResponse *ni_resp = &packet->nameinfo_response;
898 assert(length >= sizeof(NameInfoResponse));
899 assert(q->type == REQUEST_NAMEINFO);
901 q->ret = ni_resp->ret;
902 q->_errno = ni_resp->_errno;
903 q->_h_errno = ni_resp->_h_errno;
905 if (ni_resp->hostlen > 0) {
906 q->host = strndup((const char*) ni_resp + sizeof(NameInfoResponse), ni_resp->hostlen-1);
914 if (ni_resp->servlen > 0) {
915 q->serv = strndup((const char*) ni_resp + sizeof(NameInfoResponse) + ni_resp->hostlen, ni_resp->servlen-1);
923 return complete_query(resolve, q);
927 const ResResponse *res_resp = &packet->res_response;
929 assert(length >= sizeof(ResResponse));
930 assert(q->type == REQUEST_RES_QUERY || q->type == REQUEST_RES_SEARCH);
932 q->ret = res_resp->ret;
933 q->_errno = res_resp->_errno;
934 q->_h_errno = res_resp->_h_errno;
936 if (res_resp->ret >= 0) {
937 q->answer = memdup((const char *)resp + sizeof(ResResponse), res_resp->ret);
945 return complete_query(resolve, q);
953 _public_ int sd_resolve_process(sd_resolve *resolve) {
954 RESOLVE_DONT_DESTROY(resolve);
958 uint8_t space[BUFSIZE];
963 assert_return(resolve, -EINVAL);
964 assert_return(!resolve_pid_changed(resolve), -ECHILD);
966 /* We don't allow recursively invoking sd_resolve_process(). */
967 assert_return(!resolve->current, -EBUSY);
969 l = recv(resolve->fds[RESPONSE_RECV_FD], &buf, sizeof(buf), 0);
977 return -ECONNREFUSED;
979 r = handle_response(resolve, &buf.packet, (size_t) l);
986 _public_ int sd_resolve_wait(sd_resolve *resolve, uint64_t timeout_usec) {
989 assert_return(resolve, -EINVAL);
990 assert_return(!resolve_pid_changed(resolve), -ECHILD);
992 if (resolve->n_done >= resolve->n_queries)
996 r = fd_wait_for_event(resolve->fds[RESPONSE_RECV_FD], POLLIN, timeout_usec);
997 } while (r == -EINTR);
1002 return sd_resolve_process(resolve);
1005 static int alloc_query(sd_resolve *resolve, bool floating, sd_resolve_query **_q) {
1006 sd_resolve_query *q;
1012 if (resolve->n_queries >= QUERIES_MAX)
1015 r = start_threads(resolve, 1);
1019 while (resolve->query_array[resolve->current_id % QUERIES_MAX])
1020 resolve->current_id++;
1022 q = resolve->query_array[resolve->current_id % QUERIES_MAX] = new0(sd_resolve_query, 1);
1027 q->resolve = resolve;
1028 q->floating = floating;
1029 q->id = resolve->current_id++;
1032 sd_resolve_ref(resolve);
1034 LIST_PREPEND(queries, resolve->queries, q);
1035 resolve->n_queries++;
1041 _public_ int sd_resolve_getaddrinfo(
1042 sd_resolve *resolve,
1043 sd_resolve_query **_q,
1044 const char *node, const char *service,
1045 const struct addrinfo *hints,
1046 sd_resolve_getaddrinfo_handler_t callback, void *userdata) {
1048 AddrInfoRequest req = {};
1049 struct msghdr mh = {};
1050 struct iovec iov[3];
1051 sd_resolve_query *q;
1054 assert_return(resolve, -EINVAL);
1055 assert_return(node || service, -EINVAL);
1056 assert_return(callback, -EINVAL);
1057 assert_return(!resolve_pid_changed(resolve), -ECHILD);
1059 r = alloc_query(resolve, !_q, &q);
1063 q->type = REQUEST_ADDRINFO;
1064 q->getaddrinfo_handler = callback;
1065 q->userdata = userdata;
1067 req.node_len = node ? strlen(node)+1 : 0;
1068 req.service_len = service ? strlen(service)+1 : 0;
1070 req.header.id = q->id;
1071 req.header.type = REQUEST_ADDRINFO;
1072 req.header.length = sizeof(AddrInfoRequest) + req.node_len + req.service_len;
1075 req.hints_valid = true;
1076 req.ai_flags = hints->ai_flags;
1077 req.ai_family = hints->ai_family;
1078 req.ai_socktype = hints->ai_socktype;
1079 req.ai_protocol = hints->ai_protocol;
1082 iov[mh.msg_iovlen++] = (struct iovec) { .iov_base = &req, .iov_len = sizeof(AddrInfoRequest) };
1084 iov[mh.msg_iovlen++] = (struct iovec) { .iov_base = (void*) node, .iov_len = req.node_len };
1086 iov[mh.msg_iovlen++] = (struct iovec) { .iov_base = (void*) service, .iov_len = req.service_len };
1089 if (sendmsg(resolve->fds[REQUEST_SEND_FD], &mh, MSG_NOSIGNAL) < 0) {
1090 sd_resolve_query_unref(q);
1094 resolve->n_outstanding++;
1102 static int getaddrinfo_done(sd_resolve_query* q) {
1105 assert(q->getaddrinfo_handler);
1108 h_errno = q->_h_errno;
1110 return q->getaddrinfo_handler(q, q->ret, q->addrinfo, q->userdata);
1113 _public_ int sd_resolve_getnameinfo(
1114 sd_resolve *resolve,
1115 sd_resolve_query**_q,
1116 const struct sockaddr *sa, socklen_t salen,
1119 sd_resolve_getnameinfo_handler_t callback,
1122 NameInfoRequest req = {};
1123 struct msghdr mh = {};
1124 struct iovec iov[2];
1125 sd_resolve_query *q;
1128 assert_return(resolve, -EINVAL);
1129 assert_return(sa, -EINVAL);
1130 assert_return(salen >= sizeof(struct sockaddr), -EINVAL);
1131 assert_return(salen <= sizeof(union sockaddr_union), -EINVAL);
1132 assert_return((get & ~SD_RESOLVE_GET_BOTH) == 0, -EINVAL);
1133 assert_return(callback, -EINVAL);
1134 assert_return(!resolve_pid_changed(resolve), -ECHILD);
1136 r = alloc_query(resolve, !_q, &q);
1140 q->type = REQUEST_NAMEINFO;
1141 q->getnameinfo_handler = callback;
1142 q->userdata = userdata;
1144 req.header.id = q->id;
1145 req.header.type = REQUEST_NAMEINFO;
1146 req.header.length = sizeof(NameInfoRequest) + salen;
1149 req.sockaddr_len = salen;
1150 req.gethost = !!(get & SD_RESOLVE_GET_HOST);
1151 req.getserv = !!(get & SD_RESOLVE_GET_SERVICE);
1153 iov[0] = (struct iovec) { .iov_base = &req, .iov_len = sizeof(NameInfoRequest) };
1154 iov[1] = (struct iovec) { .iov_base = (void*) sa, .iov_len = salen };
1159 if (sendmsg(resolve->fds[REQUEST_SEND_FD], &mh, MSG_NOSIGNAL) < 0) {
1160 sd_resolve_query_unref(q);
1164 resolve->n_outstanding++;
1172 static int getnameinfo_done(sd_resolve_query *q) {
1176 assert(q->getnameinfo_handler);
1179 h_errno= q->_h_errno;
1181 return q->getnameinfo_handler(q, q->ret, q->host, q->serv, q->userdata);
1184 static int resolve_res(
1185 sd_resolve *resolve,
1186 sd_resolve_query **_q,
1189 int class, int type,
1190 sd_resolve_res_handler_t callback, void *userdata) {
1192 struct msghdr mh = {};
1193 struct iovec iov[2];
1194 ResRequest req = {};
1195 sd_resolve_query *q;
1198 assert_return(resolve, -EINVAL);
1199 assert_return(dname, -EINVAL);
1200 assert_return(callback, -EINVAL);
1201 assert_return(!resolve_pid_changed(resolve), -ECHILD);
1203 r = alloc_query(resolve, !_q, &q);
1208 q->res_handler = callback;
1209 q->userdata = userdata;
1211 req.dname_len = strlen(dname) + 1;
1215 req.header.id = q->id;
1216 req.header.type = qtype;
1217 req.header.length = sizeof(ResRequest) + req.dname_len;
1219 iov[0] = (struct iovec) { .iov_base = &req, .iov_len = sizeof(ResRequest) };
1220 iov[1] = (struct iovec) { .iov_base = (void*) dname, .iov_len = req.dname_len };
1225 if (sendmsg(resolve->fds[REQUEST_SEND_FD], &mh, MSG_NOSIGNAL) < 0) {
1226 sd_resolve_query_unref(q);
1230 resolve->n_outstanding++;
1238 _public_ int sd_resolve_res_query(sd_resolve *resolve, sd_resolve_query** q, const char *dname, int class, int type, sd_resolve_res_handler_t callback, void *userdata) {
1239 return resolve_res(resolve, q, REQUEST_RES_QUERY, dname, class, type, callback, userdata);
1242 _public_ int sd_resolve_res_search(sd_resolve *resolve, sd_resolve_query** q, const char *dname, int class, int type, sd_resolve_res_handler_t callback, void *userdata) {
1243 return resolve_res(resolve, q, REQUEST_RES_SEARCH, dname, class, type, callback, userdata);
1246 static int res_query_done(sd_resolve_query* q) {
1249 assert(q->res_handler);
1252 h_errno = q->_h_errno;
1254 return q->res_handler(q, q->ret, q->answer, q->userdata);
1257 _public_ sd_resolve_query* sd_resolve_query_ref(sd_resolve_query *q) {
1258 assert_return(q, NULL);
1260 assert(q->n_ref >= 1);
1266 static void resolve_freeaddrinfo(struct addrinfo *ai) {
1268 struct addrinfo *next = ai->ai_next;
1271 free(ai->ai_canonname);
1277 static void resolve_query_disconnect(sd_resolve_query *q) {
1278 sd_resolve *resolve;
1286 resolve = q->resolve;
1287 assert(resolve->n_queries > 0);
1290 assert(resolve->n_done > 0);
1294 i = q->id % QUERIES_MAX;
1295 assert(resolve->query_array[i] == q);
1296 resolve->query_array[i] = NULL;
1297 LIST_REMOVE(queries, resolve->queries, q);
1298 resolve->n_queries--;
1302 sd_resolve_unref(resolve);
1305 static void resolve_query_free(sd_resolve_query *q) {
1308 resolve_query_disconnect(q);
1310 resolve_freeaddrinfo(q->addrinfo);
1317 _public_ sd_resolve_query* sd_resolve_query_unref(sd_resolve_query* q) {
1321 assert(q->n_ref >= 1);
1325 resolve_query_free(q);
1330 _public_ int sd_resolve_query_is_done(sd_resolve_query *q) {
1331 assert_return(q, -EINVAL);
1332 assert_return(!resolve_pid_changed(q->resolve), -ECHILD);
1337 _public_ void* sd_resolve_query_set_userdata(sd_resolve_query *q, void *userdata) {
1340 assert_return(q, NULL);
1341 assert_return(!resolve_pid_changed(q->resolve), NULL);
1344 q->userdata = userdata;
1349 _public_ void* sd_resolve_query_get_userdata(sd_resolve_query *q) {
1350 assert_return(q, NULL);
1351 assert_return(!resolve_pid_changed(q->resolve), NULL);
1356 _public_ sd_resolve *sd_resolve_query_get_resolve(sd_resolve_query *q) {
1357 assert_return(q, NULL);
1358 assert_return(!resolve_pid_changed(q->resolve), NULL);
1363 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
1364 sd_resolve *resolve = userdata;
1369 r = sd_resolve_process(resolve);
1376 _public_ int sd_resolve_attach_event(sd_resolve *resolve, sd_event *event, int priority) {
1379 assert_return(resolve, -EINVAL);
1380 assert_return(!resolve->event, -EBUSY);
1382 assert(!resolve->event_source);
1385 resolve->event = sd_event_ref(event);
1387 r = sd_event_default(&resolve->event);
1392 r = sd_event_add_io(resolve->event, &resolve->event_source, resolve->fds[RESPONSE_RECV_FD], POLLIN, io_callback, resolve);
1396 r = sd_event_source_set_priority(resolve->event_source, priority);
1403 sd_resolve_detach_event(resolve);
1407 _public_ int sd_resolve_detach_event(sd_resolve *resolve) {
1408 assert_return(resolve, -EINVAL);
1410 if (!resolve->event)
1413 if (resolve->event_source) {
1414 sd_event_source_set_enabled(resolve->event_source, SD_EVENT_OFF);
1415 resolve->event_source = sd_event_source_unref(resolve->event_source);
1418 resolve->event = sd_event_unref(resolve->event);
1422 _public_ sd_event *sd_resolve_get_event(sd_resolve *resolve) {
1423 assert_return(resolve, NULL);
1425 return resolve->event;