1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2005-2008 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
30 #include <sys/prctl.h>
33 #include "sd-resolve.h"
35 #include "alloc-util.h"
36 #include "dns-domain.h"
41 #include "socket-util.h"
44 #define WORKERS_MIN 1U
45 #define WORKERS_MAX 16U
46 #define QUERIES_MAX 256U
47 #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
;
109 sd_resolve_getaddrinfo_handler_t getaddrinfo_handler
;
110 sd_resolve_getnameinfo_handler_t getnameinfo_handler
;
115 LIST_FIELDS(sd_resolve_query
, queries
);
118 typedef struct RHeader
{
124 typedef struct AddrInfoRequest
{
125 struct RHeader header
;
131 size_t node_len
, service_len
;
134 typedef struct AddrInfoResponse
{
135 struct RHeader header
;
139 /* followed by addrinfo_serialization[] */
142 typedef struct AddrInfoSerialization
{
148 size_t canonname_len
;
149 /* Followed by ai_addr amd ai_canonname with variable lengths */
150 } AddrInfoSerialization
;
152 typedef struct NameInfoRequest
{
153 struct RHeader header
;
155 socklen_t sockaddr_len
;
156 bool gethost
:1, getserv
:1;
159 typedef struct NameInfoResponse
{
160 struct RHeader header
;
161 size_t hostlen
, servlen
;
167 typedef union Packet
{
169 AddrInfoRequest addrinfo_request
;
170 AddrInfoResponse addrinfo_response
;
171 NameInfoRequest nameinfo_request
;
172 NameInfoResponse nameinfo_response
;
175 static int getaddrinfo_done(sd_resolve_query
* q
);
176 static int getnameinfo_done(sd_resolve_query
*q
);
178 static void resolve_query_disconnect(sd_resolve_query
*q
);
180 #define RESOLVE_DONT_DESTROY(resolve) \
181 _cleanup_(sd_resolve_unrefp) _unused_ sd_resolve *_dont_destroy_##resolve = sd_resolve_ref(resolve)
183 static int send_died(int out_fd
) {
186 .type
= RESPONSE_DIED
,
187 .length
= sizeof(RHeader
),
192 if (send(out_fd
, &rh
, rh
.length
, MSG_NOSIGNAL
) < 0)
198 static void *serialize_addrinfo(void *p
, const struct addrinfo
*ai
, size_t *length
, size_t maxlength
) {
199 AddrInfoSerialization s
;
205 assert(*length
<= maxlength
);
207 cnl
= ai
->ai_canonname
? strlen(ai
->ai_canonname
)+1 : 0;
208 l
= sizeof(AddrInfoSerialization
) + ai
->ai_addrlen
+ cnl
;
210 if (*length
+ l
> maxlength
)
213 s
.ai_flags
= ai
->ai_flags
;
214 s
.ai_family
= ai
->ai_family
;
215 s
.ai_socktype
= ai
->ai_socktype
;
216 s
.ai_protocol
= ai
->ai_protocol
;
217 s
.ai_addrlen
= ai
->ai_addrlen
;
218 s
.canonname_len
= cnl
;
220 memcpy((uint8_t*) p
, &s
, sizeof(AddrInfoSerialization
));
221 memcpy((uint8_t*) p
+ sizeof(AddrInfoSerialization
), ai
->ai_addr
, ai
->ai_addrlen
);
222 memcpy_safe((char*) p
+ sizeof(AddrInfoSerialization
) + ai
->ai_addrlen
,
223 ai
->ai_canonname
, cnl
);
226 return (uint8_t*) p
+ l
;
229 static int send_addrinfo_reply(
237 AddrInfoResponse resp
= {
238 .header
.type
= RESPONSE_ADDRINFO
,
240 .header
.length
= sizeof(AddrInfoResponse
),
243 ._h_errno
= _h_errno
,
246 struct msghdr mh
= {};
249 AddrInfoSerialization ais
;
250 uint8_t space
[BUFSIZE
];
255 if (ret
== 0 && ai
) {
259 for (k
= ai
; k
; k
= k
->ai_next
) {
260 p
= serialize_addrinfo(p
, k
, &resp
.header
.length
, (uint8_t*) &buffer
+ BUFSIZE
- (uint8_t*) p
);
271 iov
[0] = (struct iovec
) { .iov_base
= &resp
, .iov_len
= sizeof(AddrInfoResponse
) };
272 iov
[1] = (struct iovec
) { .iov_base
= &buffer
, .iov_len
= resp
.header
.length
- sizeof(AddrInfoResponse
) };
275 mh
.msg_iovlen
= ELEMENTSOF(iov
);
277 if (sendmsg(out_fd
, &mh
, MSG_NOSIGNAL
) < 0)
283 static int send_nameinfo_reply(
292 NameInfoResponse resp
= {
293 .header
.type
= RESPONSE_NAMEINFO
,
297 ._h_errno
= _h_errno
,
300 struct msghdr mh
= {};
306 sl
= serv
? strlen(serv
)+1 : 0;
307 hl
= host
? strlen(host
)+1 : 0;
309 resp
.header
.length
= sizeof(NameInfoResponse
) + hl
+ sl
;
313 iov
[0] = (struct iovec
) { .iov_base
= &resp
, .iov_len
= sizeof(NameInfoResponse
) };
314 iov
[1] = (struct iovec
) { .iov_base
= (void*) host
, .iov_len
= hl
};
315 iov
[2] = (struct iovec
) { .iov_base
= (void*) serv
, .iov_len
= sl
};
318 mh
.msg_iovlen
= ELEMENTSOF(iov
);
320 if (sendmsg(out_fd
, &mh
, MSG_NOSIGNAL
) < 0)
326 static int handle_request(int out_fd
, const Packet
*packet
, size_t length
) {
332 req
= &packet
->rheader
;
334 assert(length
>= sizeof(RHeader
));
335 assert(length
== req
->length
);
339 case REQUEST_ADDRINFO
: {
340 const AddrInfoRequest
*ai_req
= &packet
->addrinfo_request
;
341 struct addrinfo hints
= {}, *result
= NULL
;
342 const char *node
, *service
;
345 assert(length
>= sizeof(AddrInfoRequest
));
346 assert(length
== sizeof(AddrInfoRequest
) + ai_req
->node_len
+ ai_req
->service_len
);
348 hints
.ai_flags
= ai_req
->ai_flags
;
349 hints
.ai_family
= ai_req
->ai_family
;
350 hints
.ai_socktype
= ai_req
->ai_socktype
;
351 hints
.ai_protocol
= ai_req
->ai_protocol
;
353 node
= ai_req
->node_len
? (const char*) ai_req
+ sizeof(AddrInfoRequest
) : NULL
;
354 service
= ai_req
->service_len
? (const char*) ai_req
+ sizeof(AddrInfoRequest
) + ai_req
->node_len
: NULL
;
358 ai_req
->hints_valid
? &hints
: NULL
,
361 /* send_addrinfo_reply() frees result */
362 return send_addrinfo_reply(out_fd
, req
->id
, ret
, result
, errno
, h_errno
);
365 case REQUEST_NAMEINFO
: {
366 const NameInfoRequest
*ni_req
= &packet
->nameinfo_request
;
367 char hostbuf
[NI_MAXHOST
], servbuf
[NI_MAXSERV
];
368 union sockaddr_union sa
;
371 assert(length
>= sizeof(NameInfoRequest
));
372 assert(length
== sizeof(NameInfoRequest
) + ni_req
->sockaddr_len
);
373 assert(sizeof(sa
) >= ni_req
->sockaddr_len
);
375 memcpy(&sa
, (const uint8_t *) ni_req
+ sizeof(NameInfoRequest
), ni_req
->sockaddr_len
);
377 ret
= getnameinfo(&sa
.sa
, ni_req
->sockaddr_len
,
378 ni_req
->gethost
? hostbuf
: NULL
, ni_req
->gethost
? sizeof(hostbuf
) : 0,
379 ni_req
->getserv
? servbuf
: NULL
, ni_req
->getserv
? sizeof(servbuf
) : 0,
382 return send_nameinfo_reply(out_fd
, req
->id
, ret
,
383 ret
== 0 && ni_req
->gethost
? hostbuf
: NULL
,
384 ret
== 0 && ni_req
->getserv
? servbuf
: NULL
,
388 case REQUEST_TERMINATE
:
393 assert_not_reached("Unknown request");
399 static void* thread_worker(void *p
) {
400 sd_resolve
*resolve
= p
;
403 /* No signals in this thread please */
404 assert_se(sigfillset(&fullset
) == 0);
405 assert_se(pthread_sigmask(SIG_BLOCK
, &fullset
, NULL
) == 0);
407 /* Assign a pretty name to this thread */
408 (void) prctl(PR_SET_NAME
, (unsigned long) "sd-resolve");
410 while (!resolve
->dead
) {
413 uint8_t space
[BUFSIZE
];
417 length
= recv(resolve
->fds
[REQUEST_RECV_FD
], &buf
, sizeof(buf
), 0);
430 if (handle_request(resolve
->fds
[RESPONSE_SEND_FD
], &buf
.packet
, (size_t) length
) < 0)
434 send_died(resolve
->fds
[RESPONSE_SEND_FD
]);
439 static int start_threads(sd_resolve
*resolve
, unsigned extra
) {
443 n
= resolve
->n_outstanding
+ extra
;
444 n
= CLAMP(n
, WORKERS_MIN
, WORKERS_MAX
);
446 while (resolve
->n_valid_workers
< n
) {
448 r
= pthread_create(&resolve
->workers
[resolve
->n_valid_workers
], NULL
, thread_worker
, resolve
);
452 resolve
->n_valid_workers
++;
458 static bool resolve_pid_changed(sd_resolve
*r
) {
461 /* We don't support people creating a resolver and keeping it
462 * around after fork(). Let's complain. */
464 return r
->original_pid
!= getpid_cached();
467 _public_
int sd_resolve_new(sd_resolve
**ret
) {
468 sd_resolve
*resolve
= NULL
;
471 assert_return(ret
, -EINVAL
);
473 resolve
= new0(sd_resolve
, 1);
478 resolve
->original_pid
= getpid_cached();
480 for (i
= 0; i
< _FD_MAX
; i
++)
481 resolve
->fds
[i
] = -1;
483 r
= socketpair(PF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0, resolve
->fds
+ REQUEST_RECV_FD
);
489 r
= socketpair(PF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0, resolve
->fds
+ RESPONSE_RECV_FD
);
495 fd_inc_sndbuf(resolve
->fds
[REQUEST_SEND_FD
], QUERIES_MAX
* BUFSIZE
);
496 fd_inc_rcvbuf(resolve
->fds
[REQUEST_RECV_FD
], QUERIES_MAX
* BUFSIZE
);
497 fd_inc_sndbuf(resolve
->fds
[RESPONSE_SEND_FD
], QUERIES_MAX
* BUFSIZE
);
498 fd_inc_rcvbuf(resolve
->fds
[RESPONSE_RECV_FD
], QUERIES_MAX
* BUFSIZE
);
500 fd_nonblock(resolve
->fds
[RESPONSE_RECV_FD
], true);
506 sd_resolve_unref(resolve
);
510 _public_
int sd_resolve_default(sd_resolve
**ret
) {
512 static thread_local sd_resolve
*default_resolve
= NULL
;
513 sd_resolve
*e
= NULL
;
517 return !!default_resolve
;
519 if (default_resolve
) {
520 *ret
= sd_resolve_ref(default_resolve
);
524 r
= sd_resolve_new(&e
);
528 e
->default_resolve_ptr
= &default_resolve
;
536 _public_
int sd_resolve_get_tid(sd_resolve
*resolve
, pid_t
*tid
) {
537 assert_return(resolve
, -EINVAL
);
538 assert_return(tid
, -EINVAL
);
539 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
541 if (resolve
->tid
!= 0) {
547 return sd_event_get_tid(resolve
->event
, tid
);
552 static void resolve_free(sd_resolve
*resolve
) {
559 while ((q
= resolve
->queries
)) {
561 resolve_query_disconnect(q
);
562 sd_resolve_query_unref(q
);
565 if (resolve
->default_resolve_ptr
)
566 *(resolve
->default_resolve_ptr
) = NULL
;
568 resolve
->dead
= true;
570 sd_resolve_detach_event(resolve
);
572 if (resolve
->fds
[REQUEST_SEND_FD
] >= 0) {
575 .type
= REQUEST_TERMINATE
,
576 .length
= sizeof(req
)
579 /* Send one termination packet for each worker */
580 for (i
= 0; i
< resolve
->n_valid_workers
; i
++)
581 (void) send(resolve
->fds
[REQUEST_SEND_FD
], &req
, req
.length
, MSG_NOSIGNAL
);
584 /* Now terminate them and wait until they are gone.
585 If we get an error than most likely the thread already exited. */
586 for (i
= 0; i
< resolve
->n_valid_workers
; i
++)
587 (void) pthread_join(resolve
->workers
[i
], NULL
);
589 /* Close all communication channels */
590 close_many(resolve
->fds
, _FD_MAX
);
594 _public_ sd_resolve
* sd_resolve_ref(sd_resolve
*resolve
) {
595 assert_return(resolve
, NULL
);
597 assert(resolve
->n_ref
>= 1);
603 _public_ sd_resolve
* sd_resolve_unref(sd_resolve
*resolve
) {
608 assert(resolve
->n_ref
>= 1);
611 if (resolve
->n_ref
<= 0)
612 resolve_free(resolve
);
617 _public_
int sd_resolve_get_fd(sd_resolve
*resolve
) {
618 assert_return(resolve
, -EINVAL
);
619 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
621 return resolve
->fds
[RESPONSE_RECV_FD
];
624 _public_
int sd_resolve_get_events(sd_resolve
*resolve
) {
625 assert_return(resolve
, -EINVAL
);
626 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
628 return resolve
->n_queries
> resolve
->n_done
? POLLIN
: 0;
631 _public_
int sd_resolve_get_timeout(sd_resolve
*resolve
, uint64_t *usec
) {
632 assert_return(resolve
, -EINVAL
);
633 assert_return(usec
, -EINVAL
);
634 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
636 *usec
= (uint64_t) -1;
640 static sd_resolve_query
*lookup_query(sd_resolve
*resolve
, unsigned id
) {
645 q
= resolve
->query_array
[id
% QUERIES_MAX
];
653 static int complete_query(sd_resolve
*resolve
, sd_resolve_query
*q
) {
658 assert(q
->resolve
== resolve
);
663 resolve
->current
= sd_resolve_query_ref(q
);
667 case REQUEST_ADDRINFO
:
668 r
= getaddrinfo_done(q
);
671 case REQUEST_NAMEINFO
:
672 r
= getnameinfo_done(q
);
676 assert_not_reached("Cannot complete unknown query type");
679 resolve
->current
= NULL
;
682 resolve_query_disconnect(q
);
683 sd_resolve_query_unref(q
);
686 sd_resolve_query_unref(q
);
691 static int unserialize_addrinfo(const void **p
, size_t *length
, struct addrinfo
**ret_ai
) {
692 AddrInfoSerialization s
;
701 if (*length
< sizeof(AddrInfoSerialization
))
704 memcpy(&s
, *p
, sizeof(s
));
706 l
= sizeof(AddrInfoSerialization
) + s
.ai_addrlen
+ s
.canonname_len
;
710 ai
= new0(struct addrinfo
, 1);
714 ai
->ai_flags
= s
.ai_flags
;
715 ai
->ai_family
= s
.ai_family
;
716 ai
->ai_socktype
= s
.ai_socktype
;
717 ai
->ai_protocol
= s
.ai_protocol
;
718 ai
->ai_addrlen
= s
.ai_addrlen
;
720 if (s
.ai_addrlen
> 0) {
721 ai
->ai_addr
= memdup((const uint8_t*) *p
+ sizeof(AddrInfoSerialization
), s
.ai_addrlen
);
728 if (s
.canonname_len
> 0) {
729 ai
->ai_canonname
= memdup((const uint8_t*) *p
+ sizeof(AddrInfoSerialization
) + s
.ai_addrlen
, s
.canonname_len
);
730 if (!ai
->ai_canonname
) {
739 *p
= ((const uint8_t*) *p
) + l
;
744 static int handle_response(sd_resolve
*resolve
, const Packet
*packet
, size_t length
) {
751 resp
= &packet
->rheader
;
753 assert(length
>= sizeof(RHeader
));
754 assert(length
== resp
->length
);
756 if (resp
->type
== RESPONSE_DIED
) {
757 resolve
->dead
= true;
761 assert(resolve
->n_outstanding
> 0);
762 resolve
->n_outstanding
--;
764 q
= lookup_query(resolve
, resp
->id
);
768 switch (resp
->type
) {
770 case RESPONSE_ADDRINFO
: {
771 const AddrInfoResponse
*ai_resp
= &packet
->addrinfo_response
;
774 struct addrinfo
*prev
= NULL
;
776 assert(length
>= sizeof(AddrInfoResponse
));
777 assert(q
->type
== REQUEST_ADDRINFO
);
779 q
->ret
= ai_resp
->ret
;
780 q
->_errno
= ai_resp
->_errno
;
781 q
->_h_errno
= ai_resp
->_h_errno
;
783 l
= length
- sizeof(AddrInfoResponse
);
784 p
= (const uint8_t*) resp
+ sizeof(AddrInfoResponse
);
787 struct addrinfo
*ai
= NULL
;
789 r
= unserialize_addrinfo(&p
, &l
, &ai
);
794 freeaddrinfo(q
->addrinfo
);
807 return complete_query(resolve
, q
);
810 case RESPONSE_NAMEINFO
: {
811 const NameInfoResponse
*ni_resp
= &packet
->nameinfo_response
;
813 assert(length
>= sizeof(NameInfoResponse
));
814 assert(q
->type
== REQUEST_NAMEINFO
);
816 if (ni_resp
->hostlen
> DNS_HOSTNAME_MAX
||
817 ni_resp
->servlen
> DNS_HOSTNAME_MAX
||
818 sizeof(NameInfoResponse
) + ni_resp
->hostlen
+ ni_resp
->servlen
> length
+ 2) {
824 q
->ret
= ni_resp
->ret
;
825 q
->_errno
= ni_resp
->_errno
;
826 q
->_h_errno
= ni_resp
->_h_errno
;
828 if (ni_resp
->hostlen
> 0) {
829 q
->host
= strndup((const char*) ni_resp
+ sizeof(NameInfoResponse
),
838 if (ni_resp
->servlen
> 0) {
839 q
->serv
= strndup((const char*) ni_resp
+ sizeof(NameInfoResponse
) + ni_resp
->hostlen
,
849 return complete_query(resolve
, q
);
857 _public_
int sd_resolve_process(sd_resolve
*resolve
) {
858 RESOLVE_DONT_DESTROY(resolve
);
862 uint8_t space
[BUFSIZE
];
867 assert_return(resolve
, -EINVAL
);
868 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
870 /* We don't allow recursively invoking sd_resolve_process(). */
871 assert_return(!resolve
->current
, -EBUSY
);
873 l
= recv(resolve
->fds
[RESPONSE_RECV_FD
], &buf
, sizeof(buf
), 0);
881 return -ECONNREFUSED
;
883 r
= handle_response(resolve
, &buf
.packet
, (size_t) l
);
890 _public_
int sd_resolve_wait(sd_resolve
*resolve
, uint64_t timeout_usec
) {
893 assert_return(resolve
, -EINVAL
);
894 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
896 if (resolve
->n_done
>= resolve
->n_queries
)
900 r
= fd_wait_for_event(resolve
->fds
[RESPONSE_RECV_FD
], POLLIN
, timeout_usec
);
901 } while (r
== -EINTR
);
908 return sd_resolve_process(resolve
);
911 static int alloc_query(sd_resolve
*resolve
, bool floating
, sd_resolve_query
**_q
) {
918 if (resolve
->n_queries
>= QUERIES_MAX
)
921 r
= start_threads(resolve
, 1);
925 while (resolve
->query_array
[resolve
->current_id
% QUERIES_MAX
])
926 resolve
->current_id
++;
928 q
= resolve
->query_array
[resolve
->current_id
% QUERIES_MAX
] = new0(sd_resolve_query
, 1);
933 q
->resolve
= resolve
;
934 q
->floating
= floating
;
935 q
->id
= resolve
->current_id
++;
938 sd_resolve_ref(resolve
);
940 LIST_PREPEND(queries
, resolve
->queries
, q
);
941 resolve
->n_queries
++;
947 _public_
int sd_resolve_getaddrinfo(
949 sd_resolve_query
**_q
,
950 const char *node
, const char *service
,
951 const struct addrinfo
*hints
,
952 sd_resolve_getaddrinfo_handler_t callback
, void *userdata
) {
954 AddrInfoRequest req
= {};
955 struct msghdr mh
= {};
960 assert_return(resolve
, -EINVAL
);
961 assert_return(node
|| service
, -EINVAL
);
962 assert_return(callback
, -EINVAL
);
963 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
965 r
= alloc_query(resolve
, !_q
, &q
);
969 q
->type
= REQUEST_ADDRINFO
;
970 q
->getaddrinfo_handler
= callback
;
971 q
->userdata
= userdata
;
973 req
.node_len
= node
? strlen(node
)+1 : 0;
974 req
.service_len
= service
? strlen(service
)+1 : 0;
976 req
.header
.id
= q
->id
;
977 req
.header
.type
= REQUEST_ADDRINFO
;
978 req
.header
.length
= sizeof(AddrInfoRequest
) + req
.node_len
+ req
.service_len
;
981 req
.hints_valid
= true;
982 req
.ai_flags
= hints
->ai_flags
;
983 req
.ai_family
= hints
->ai_family
;
984 req
.ai_socktype
= hints
->ai_socktype
;
985 req
.ai_protocol
= hints
->ai_protocol
;
988 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= &req
, .iov_len
= sizeof(AddrInfoRequest
) };
990 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= (void*) node
, .iov_len
= req
.node_len
};
992 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= (void*) service
, .iov_len
= req
.service_len
};
995 if (sendmsg(resolve
->fds
[REQUEST_SEND_FD
], &mh
, MSG_NOSIGNAL
) < 0) {
996 sd_resolve_query_unref(q
);
1000 resolve
->n_outstanding
++;
1008 static int getaddrinfo_done(sd_resolve_query
* q
) {
1011 assert(q
->getaddrinfo_handler
);
1014 h_errno
= q
->_h_errno
;
1016 return q
->getaddrinfo_handler(q
, q
->ret
, q
->addrinfo
, q
->userdata
);
1019 _public_
int sd_resolve_getnameinfo(
1020 sd_resolve
*resolve
,
1021 sd_resolve_query
**_q
,
1022 const struct sockaddr
*sa
, socklen_t salen
,
1025 sd_resolve_getnameinfo_handler_t callback
,
1028 NameInfoRequest req
= {};
1029 struct msghdr mh
= {};
1030 struct iovec iov
[2];
1031 sd_resolve_query
*q
;
1034 assert_return(resolve
, -EINVAL
);
1035 assert_return(sa
, -EINVAL
);
1036 assert_return(salen
>= sizeof(struct sockaddr
), -EINVAL
);
1037 assert_return(salen
<= sizeof(union sockaddr_union
), -EINVAL
);
1038 assert_return((get
& ~SD_RESOLVE_GET_BOTH
) == 0, -EINVAL
);
1039 assert_return(callback
, -EINVAL
);
1040 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
1042 r
= alloc_query(resolve
, !_q
, &q
);
1046 q
->type
= REQUEST_NAMEINFO
;
1047 q
->getnameinfo_handler
= callback
;
1048 q
->userdata
= userdata
;
1050 req
.header
.id
= q
->id
;
1051 req
.header
.type
= REQUEST_NAMEINFO
;
1052 req
.header
.length
= sizeof(NameInfoRequest
) + salen
;
1055 req
.sockaddr_len
= salen
;
1056 req
.gethost
= !!(get
& SD_RESOLVE_GET_HOST
);
1057 req
.getserv
= !!(get
& SD_RESOLVE_GET_SERVICE
);
1059 iov
[0] = (struct iovec
) { .iov_base
= &req
, .iov_len
= sizeof(NameInfoRequest
) };
1060 iov
[1] = (struct iovec
) { .iov_base
= (void*) sa
, .iov_len
= salen
};
1065 if (sendmsg(resolve
->fds
[REQUEST_SEND_FD
], &mh
, MSG_NOSIGNAL
) < 0) {
1066 sd_resolve_query_unref(q
);
1070 resolve
->n_outstanding
++;
1078 static int getnameinfo_done(sd_resolve_query
*q
) {
1082 assert(q
->getnameinfo_handler
);
1085 h_errno
= q
->_h_errno
;
1087 return q
->getnameinfo_handler(q
, q
->ret
, q
->host
, q
->serv
, q
->userdata
);
1090 _public_ sd_resolve_query
* sd_resolve_query_ref(sd_resolve_query
*q
) {
1091 assert_return(q
, NULL
);
1093 assert(q
->n_ref
>= 1);
1099 static void resolve_freeaddrinfo(struct addrinfo
*ai
) {
1101 struct addrinfo
*next
= ai
->ai_next
;
1104 free(ai
->ai_canonname
);
1110 static void resolve_query_disconnect(sd_resolve_query
*q
) {
1111 sd_resolve
*resolve
;
1119 resolve
= q
->resolve
;
1120 assert(resolve
->n_queries
> 0);
1123 assert(resolve
->n_done
> 0);
1127 i
= q
->id
% QUERIES_MAX
;
1128 assert(resolve
->query_array
[i
] == q
);
1129 resolve
->query_array
[i
] = NULL
;
1130 LIST_REMOVE(queries
, resolve
->queries
, q
);
1131 resolve
->n_queries
--;
1135 sd_resolve_unref(resolve
);
1138 static void resolve_query_free(sd_resolve_query
*q
) {
1141 resolve_query_disconnect(q
);
1143 resolve_freeaddrinfo(q
->addrinfo
);
1149 _public_ sd_resolve_query
* sd_resolve_query_unref(sd_resolve_query
* q
) {
1153 assert(q
->n_ref
>= 1);
1157 resolve_query_free(q
);
1162 _public_
int sd_resolve_query_is_done(sd_resolve_query
*q
) {
1163 assert_return(q
, -EINVAL
);
1164 assert_return(!resolve_pid_changed(q
->resolve
), -ECHILD
);
1169 _public_
void* sd_resolve_query_set_userdata(sd_resolve_query
*q
, void *userdata
) {
1172 assert_return(q
, NULL
);
1173 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1176 q
->userdata
= userdata
;
1181 _public_
void* sd_resolve_query_get_userdata(sd_resolve_query
*q
) {
1182 assert_return(q
, NULL
);
1183 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1188 _public_ sd_resolve
*sd_resolve_query_get_resolve(sd_resolve_query
*q
) {
1189 assert_return(q
, NULL
);
1190 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1195 static int io_callback(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
1196 sd_resolve
*resolve
= userdata
;
1201 r
= sd_resolve_process(resolve
);
1208 _public_
int sd_resolve_attach_event(sd_resolve
*resolve
, sd_event
*event
, int64_t priority
) {
1211 assert_return(resolve
, -EINVAL
);
1212 assert_return(!resolve
->event
, -EBUSY
);
1214 assert(!resolve
->event_source
);
1217 resolve
->event
= sd_event_ref(event
);
1219 r
= sd_event_default(&resolve
->event
);
1224 r
= sd_event_add_io(resolve
->event
, &resolve
->event_source
, resolve
->fds
[RESPONSE_RECV_FD
], POLLIN
, io_callback
, resolve
);
1228 r
= sd_event_source_set_priority(resolve
->event_source
, priority
);
1235 sd_resolve_detach_event(resolve
);
1239 _public_
int sd_resolve_detach_event(sd_resolve
*resolve
) {
1240 assert_return(resolve
, -EINVAL
);
1242 if (!resolve
->event
)
1245 if (resolve
->event_source
) {
1246 sd_event_source_set_enabled(resolve
->event_source
, SD_EVENT_OFF
);
1247 resolve
->event_source
= sd_event_source_unref(resolve
->event_source
);
1250 resolve
->event
= sd_event_unref(resolve
->event
);
1254 _public_ sd_event
*sd_resolve_get_event(sd_resolve
*resolve
) {
1255 assert_return(resolve
, NULL
);
1257 return resolve
->event
;