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"
43 #include "process-util.h"
45 #define WORKERS_MIN 1U
46 #define WORKERS_MAX 16U
47 #define QUERIES_MAX 256U
48 #define BUFSIZE 10240U
75 pthread_t workers
[WORKERS_MAX
];
76 unsigned n_valid_workers
;
79 sd_resolve_query
* query_array
[QUERIES_MAX
];
80 unsigned n_queries
, n_done
, n_outstanding
;
82 sd_event_source
*event_source
;
85 sd_resolve_query
*current
;
87 sd_resolve
**default_resolve_ptr
;
90 LIST_HEAD(sd_resolve_query
, queries
);
93 struct sd_resolve_query
{
106 struct addrinfo
*addrinfo
;
110 sd_resolve_getaddrinfo_handler_t getaddrinfo_handler
;
111 sd_resolve_getnameinfo_handler_t getnameinfo_handler
;
116 LIST_FIELDS(sd_resolve_query
, queries
);
119 typedef struct RHeader
{
125 typedef struct AddrInfoRequest
{
126 struct RHeader header
;
132 size_t node_len
, service_len
;
135 typedef struct AddrInfoResponse
{
136 struct RHeader header
;
140 /* followed by addrinfo_serialization[] */
143 typedef struct AddrInfoSerialization
{
149 size_t canonname_len
;
150 /* Followed by ai_addr amd ai_canonname with variable lengths */
151 } AddrInfoSerialization
;
153 typedef struct NameInfoRequest
{
154 struct RHeader header
;
156 socklen_t sockaddr_len
;
157 bool gethost
:1, getserv
:1;
160 typedef struct NameInfoResponse
{
161 struct RHeader header
;
162 size_t hostlen
, servlen
;
168 typedef union Packet
{
170 AddrInfoRequest addrinfo_request
;
171 AddrInfoResponse addrinfo_response
;
172 NameInfoRequest nameinfo_request
;
173 NameInfoResponse nameinfo_response
;
176 static int getaddrinfo_done(sd_resolve_query
* q
);
177 static int getnameinfo_done(sd_resolve_query
*q
);
179 static void resolve_query_disconnect(sd_resolve_query
*q
);
181 #define RESOLVE_DONT_DESTROY(resolve) \
182 _cleanup_(sd_resolve_unrefp) _unused_ sd_resolve *_dont_destroy_##resolve = sd_resolve_ref(resolve)
184 static int send_died(int out_fd
) {
187 .type
= RESPONSE_DIED
,
188 .length
= sizeof(RHeader
),
193 if (send(out_fd
, &rh
, rh
.length
, MSG_NOSIGNAL
) < 0)
199 static void *serialize_addrinfo(void *p
, const struct addrinfo
*ai
, size_t *length
, size_t maxlength
) {
200 AddrInfoSerialization s
;
206 assert(*length
<= maxlength
);
208 cnl
= ai
->ai_canonname
? strlen(ai
->ai_canonname
)+1 : 0;
209 l
= sizeof(AddrInfoSerialization
) + ai
->ai_addrlen
+ cnl
;
211 if (*length
+ l
> maxlength
)
214 s
.ai_flags
= ai
->ai_flags
;
215 s
.ai_family
= ai
->ai_family
;
216 s
.ai_socktype
= ai
->ai_socktype
;
217 s
.ai_protocol
= ai
->ai_protocol
;
218 s
.ai_addrlen
= ai
->ai_addrlen
;
219 s
.canonname_len
= cnl
;
221 memcpy((uint8_t*) p
, &s
, sizeof(AddrInfoSerialization
));
222 memcpy((uint8_t*) p
+ sizeof(AddrInfoSerialization
), ai
->ai_addr
, ai
->ai_addrlen
);
223 memcpy_safe((char*) p
+ sizeof(AddrInfoSerialization
) + ai
->ai_addrlen
,
224 ai
->ai_canonname
, cnl
);
227 return (uint8_t*) p
+ l
;
230 static int send_addrinfo_reply(
238 AddrInfoResponse resp
= {
239 .header
.type
= RESPONSE_ADDRINFO
,
241 .header
.length
= sizeof(AddrInfoResponse
),
244 ._h_errno
= _h_errno
,
247 struct msghdr mh
= {};
250 AddrInfoSerialization ais
;
251 uint8_t space
[BUFSIZE
];
256 if (ret
== 0 && ai
) {
260 for (k
= ai
; k
; k
= k
->ai_next
) {
261 p
= serialize_addrinfo(p
, k
, &resp
.header
.length
, (uint8_t*) &buffer
+ BUFSIZE
- (uint8_t*) p
);
272 iov
[0] = (struct iovec
) { .iov_base
= &resp
, .iov_len
= sizeof(AddrInfoResponse
) };
273 iov
[1] = (struct iovec
) { .iov_base
= &buffer
, .iov_len
= resp
.header
.length
- sizeof(AddrInfoResponse
) };
276 mh
.msg_iovlen
= ELEMENTSOF(iov
);
278 if (sendmsg(out_fd
, &mh
, MSG_NOSIGNAL
) < 0)
284 static int send_nameinfo_reply(
293 NameInfoResponse resp
= {
294 .header
.type
= RESPONSE_NAMEINFO
,
298 ._h_errno
= _h_errno
,
301 struct msghdr mh
= {};
307 sl
= serv
? strlen(serv
)+1 : 0;
308 hl
= host
? strlen(host
)+1 : 0;
310 resp
.header
.length
= sizeof(NameInfoResponse
) + hl
+ sl
;
314 iov
[0] = (struct iovec
) { .iov_base
= &resp
, .iov_len
= sizeof(NameInfoResponse
) };
315 iov
[1] = (struct iovec
) { .iov_base
= (void*) host
, .iov_len
= hl
};
316 iov
[2] = (struct iovec
) { .iov_base
= (void*) serv
, .iov_len
= sl
};
319 mh
.msg_iovlen
= ELEMENTSOF(iov
);
321 if (sendmsg(out_fd
, &mh
, MSG_NOSIGNAL
) < 0)
327 static int handle_request(int out_fd
, const Packet
*packet
, size_t length
) {
333 req
= &packet
->rheader
;
335 assert(length
>= sizeof(RHeader
));
336 assert(length
== req
->length
);
340 case REQUEST_ADDRINFO
: {
341 const AddrInfoRequest
*ai_req
= &packet
->addrinfo_request
;
342 struct addrinfo hints
= {}, *result
= NULL
;
343 const char *node
, *service
;
346 assert(length
>= sizeof(AddrInfoRequest
));
347 assert(length
== sizeof(AddrInfoRequest
) + ai_req
->node_len
+ ai_req
->service_len
);
349 hints
.ai_flags
= ai_req
->ai_flags
;
350 hints
.ai_family
= ai_req
->ai_family
;
351 hints
.ai_socktype
= ai_req
->ai_socktype
;
352 hints
.ai_protocol
= ai_req
->ai_protocol
;
354 node
= ai_req
->node_len
? (const char*) ai_req
+ sizeof(AddrInfoRequest
) : NULL
;
355 service
= ai_req
->service_len
? (const char*) ai_req
+ sizeof(AddrInfoRequest
) + ai_req
->node_len
: NULL
;
359 ai_req
->hints_valid
? &hints
: NULL
,
362 /* send_addrinfo_reply() frees result */
363 return send_addrinfo_reply(out_fd
, req
->id
, ret
, result
, errno
, h_errno
);
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
;
372 assert(length
>= sizeof(NameInfoRequest
));
373 assert(length
== sizeof(NameInfoRequest
) + ni_req
->sockaddr_len
);
374 assert(sizeof(sa
) >= ni_req
->sockaddr_len
);
376 memcpy(&sa
, (const uint8_t *) ni_req
+ sizeof(NameInfoRequest
), ni_req
->sockaddr_len
);
378 ret
= getnameinfo(&sa
.sa
, ni_req
->sockaddr_len
,
379 ni_req
->gethost
? hostbuf
: NULL
, ni_req
->gethost
? sizeof(hostbuf
) : 0,
380 ni_req
->getserv
? servbuf
: NULL
, ni_req
->getserv
? sizeof(servbuf
) : 0,
383 return send_nameinfo_reply(out_fd
, req
->id
, ret
,
384 ret
== 0 && ni_req
->gethost
? hostbuf
: NULL
,
385 ret
== 0 && ni_req
->getserv
? servbuf
: NULL
,
389 case REQUEST_TERMINATE
:
394 assert_not_reached("Unknown request");
400 static void* thread_worker(void *p
) {
401 sd_resolve
*resolve
= p
;
403 /* Assign a pretty name to this thread */
404 (void) pthread_setname_np(pthread_self(), "sd-resolve");
406 while (!resolve
->dead
) {
409 uint8_t space
[BUFSIZE
];
413 length
= recv(resolve
->fds
[REQUEST_RECV_FD
], &buf
, sizeof(buf
), 0);
426 if (handle_request(resolve
->fds
[RESPONSE_SEND_FD
], &buf
.packet
, (size_t) length
) < 0)
430 send_died(resolve
->fds
[RESPONSE_SEND_FD
]);
435 static int start_threads(sd_resolve
*resolve
, unsigned extra
) {
436 sigset_t ss
, saved_ss
;
440 if (sigfillset(&ss
) < 0)
443 /* No signals in forked off threads please. We set the mask before forking, so that the threads never exist
444 * with a different mask than a fully blocked one */
445 r
= pthread_sigmask(SIG_BLOCK
, &ss
, &saved_ss
);
449 n
= resolve
->n_outstanding
+ extra
;
450 n
= CLAMP(n
, WORKERS_MIN
, WORKERS_MAX
);
452 while (resolve
->n_valid_workers
< n
) {
454 r
= pthread_create(&resolve
->workers
[resolve
->n_valid_workers
], NULL
, thread_worker
, resolve
);
460 resolve
->n_valid_workers
++;
466 k
= pthread_sigmask(SIG_SETMASK
, &saved_ss
, NULL
);
473 static bool resolve_pid_changed(sd_resolve
*r
) {
476 /* We don't support people creating a resolver and keeping it
477 * around after fork(). Let's complain. */
479 return r
->original_pid
!= getpid_cached();
482 _public_
int sd_resolve_new(sd_resolve
**ret
) {
483 sd_resolve
*resolve
= NULL
;
486 assert_return(ret
, -EINVAL
);
488 resolve
= new0(sd_resolve
, 1);
493 resolve
->original_pid
= getpid_cached();
495 for (i
= 0; i
< _FD_MAX
; i
++)
496 resolve
->fds
[i
] = -1;
498 r
= socketpair(PF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0, resolve
->fds
+ REQUEST_RECV_FD
);
504 r
= socketpair(PF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0, resolve
->fds
+ RESPONSE_RECV_FD
);
510 fd_inc_sndbuf(resolve
->fds
[REQUEST_SEND_FD
], QUERIES_MAX
* BUFSIZE
);
511 fd_inc_rcvbuf(resolve
->fds
[REQUEST_RECV_FD
], QUERIES_MAX
* BUFSIZE
);
512 fd_inc_sndbuf(resolve
->fds
[RESPONSE_SEND_FD
], QUERIES_MAX
* BUFSIZE
);
513 fd_inc_rcvbuf(resolve
->fds
[RESPONSE_RECV_FD
], QUERIES_MAX
* BUFSIZE
);
515 fd_nonblock(resolve
->fds
[RESPONSE_RECV_FD
], true);
521 sd_resolve_unref(resolve
);
525 _public_
int sd_resolve_default(sd_resolve
**ret
) {
527 static thread_local sd_resolve
*default_resolve
= NULL
;
528 sd_resolve
*e
= NULL
;
532 return !!default_resolve
;
534 if (default_resolve
) {
535 *ret
= sd_resolve_ref(default_resolve
);
539 r
= sd_resolve_new(&e
);
543 e
->default_resolve_ptr
= &default_resolve
;
551 _public_
int sd_resolve_get_tid(sd_resolve
*resolve
, pid_t
*tid
) {
552 assert_return(resolve
, -EINVAL
);
553 assert_return(tid
, -EINVAL
);
554 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
556 if (resolve
->tid
!= 0) {
562 return sd_event_get_tid(resolve
->event
, tid
);
567 static void resolve_free(sd_resolve
*resolve
) {
574 while ((q
= resolve
->queries
)) {
576 resolve_query_disconnect(q
);
577 sd_resolve_query_unref(q
);
580 if (resolve
->default_resolve_ptr
)
581 *(resolve
->default_resolve_ptr
) = NULL
;
583 resolve
->dead
= true;
585 sd_resolve_detach_event(resolve
);
587 if (resolve
->fds
[REQUEST_SEND_FD
] >= 0) {
590 .type
= REQUEST_TERMINATE
,
591 .length
= sizeof(req
)
594 /* Send one termination packet for each worker */
595 for (i
= 0; i
< resolve
->n_valid_workers
; i
++)
596 (void) send(resolve
->fds
[REQUEST_SEND_FD
], &req
, req
.length
, MSG_NOSIGNAL
);
599 /* Now terminate them and wait until they are gone.
600 If we get an error than most likely the thread already exited. */
601 for (i
= 0; i
< resolve
->n_valid_workers
; i
++)
602 (void) pthread_join(resolve
->workers
[i
], NULL
);
604 /* Close all communication channels */
605 close_many(resolve
->fds
, _FD_MAX
);
609 _public_ sd_resolve
* sd_resolve_ref(sd_resolve
*resolve
) {
610 assert_return(resolve
, NULL
);
612 assert(resolve
->n_ref
>= 1);
618 _public_ sd_resolve
* sd_resolve_unref(sd_resolve
*resolve
) {
623 assert(resolve
->n_ref
>= 1);
626 if (resolve
->n_ref
<= 0)
627 resolve_free(resolve
);
632 _public_
int sd_resolve_get_fd(sd_resolve
*resolve
) {
633 assert_return(resolve
, -EINVAL
);
634 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
636 return resolve
->fds
[RESPONSE_RECV_FD
];
639 _public_
int sd_resolve_get_events(sd_resolve
*resolve
) {
640 assert_return(resolve
, -EINVAL
);
641 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
643 return resolve
->n_queries
> resolve
->n_done
? POLLIN
: 0;
646 _public_
int sd_resolve_get_timeout(sd_resolve
*resolve
, uint64_t *usec
) {
647 assert_return(resolve
, -EINVAL
);
648 assert_return(usec
, -EINVAL
);
649 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
651 *usec
= (uint64_t) -1;
655 static sd_resolve_query
*lookup_query(sd_resolve
*resolve
, unsigned id
) {
660 q
= resolve
->query_array
[id
% QUERIES_MAX
];
668 static int complete_query(sd_resolve
*resolve
, sd_resolve_query
*q
) {
673 assert(q
->resolve
== resolve
);
678 resolve
->current
= sd_resolve_query_ref(q
);
682 case REQUEST_ADDRINFO
:
683 r
= getaddrinfo_done(q
);
686 case REQUEST_NAMEINFO
:
687 r
= getnameinfo_done(q
);
691 assert_not_reached("Cannot complete unknown query type");
694 resolve
->current
= NULL
;
697 resolve_query_disconnect(q
);
698 sd_resolve_query_unref(q
);
701 sd_resolve_query_unref(q
);
706 static int unserialize_addrinfo(const void **p
, size_t *length
, struct addrinfo
**ret_ai
) {
707 AddrInfoSerialization s
;
716 if (*length
< sizeof(AddrInfoSerialization
))
719 memcpy(&s
, *p
, sizeof(s
));
721 l
= sizeof(AddrInfoSerialization
) + s
.ai_addrlen
+ s
.canonname_len
;
725 ai
= new0(struct addrinfo
, 1);
729 ai
->ai_flags
= s
.ai_flags
;
730 ai
->ai_family
= s
.ai_family
;
731 ai
->ai_socktype
= s
.ai_socktype
;
732 ai
->ai_protocol
= s
.ai_protocol
;
733 ai
->ai_addrlen
= s
.ai_addrlen
;
735 if (s
.ai_addrlen
> 0) {
736 ai
->ai_addr
= memdup((const uint8_t*) *p
+ sizeof(AddrInfoSerialization
), s
.ai_addrlen
);
743 if (s
.canonname_len
> 0) {
744 ai
->ai_canonname
= memdup((const uint8_t*) *p
+ sizeof(AddrInfoSerialization
) + s
.ai_addrlen
, s
.canonname_len
);
745 if (!ai
->ai_canonname
) {
754 *p
= ((const uint8_t*) *p
) + l
;
759 static int handle_response(sd_resolve
*resolve
, const Packet
*packet
, size_t length
) {
766 resp
= &packet
->rheader
;
768 assert(length
>= sizeof(RHeader
));
769 assert(length
== resp
->length
);
771 if (resp
->type
== RESPONSE_DIED
) {
772 resolve
->dead
= true;
776 assert(resolve
->n_outstanding
> 0);
777 resolve
->n_outstanding
--;
779 q
= lookup_query(resolve
, resp
->id
);
783 switch (resp
->type
) {
785 case RESPONSE_ADDRINFO
: {
786 const AddrInfoResponse
*ai_resp
= &packet
->addrinfo_response
;
789 struct addrinfo
*prev
= NULL
;
791 assert(length
>= sizeof(AddrInfoResponse
));
792 assert(q
->type
== REQUEST_ADDRINFO
);
794 q
->ret
= ai_resp
->ret
;
795 q
->_errno
= ai_resp
->_errno
;
796 q
->_h_errno
= ai_resp
->_h_errno
;
798 l
= length
- sizeof(AddrInfoResponse
);
799 p
= (const uint8_t*) resp
+ sizeof(AddrInfoResponse
);
802 struct addrinfo
*ai
= NULL
;
804 r
= unserialize_addrinfo(&p
, &l
, &ai
);
809 freeaddrinfo(q
->addrinfo
);
822 return complete_query(resolve
, q
);
825 case RESPONSE_NAMEINFO
: {
826 const NameInfoResponse
*ni_resp
= &packet
->nameinfo_response
;
828 assert(length
>= sizeof(NameInfoResponse
));
829 assert(q
->type
== REQUEST_NAMEINFO
);
831 if (ni_resp
->hostlen
> DNS_HOSTNAME_MAX
||
832 ni_resp
->servlen
> DNS_HOSTNAME_MAX
||
833 sizeof(NameInfoResponse
) + ni_resp
->hostlen
+ ni_resp
->servlen
> length
+ 2) {
839 q
->ret
= ni_resp
->ret
;
840 q
->_errno
= ni_resp
->_errno
;
841 q
->_h_errno
= ni_resp
->_h_errno
;
843 if (ni_resp
->hostlen
> 0) {
844 q
->host
= strndup((const char*) ni_resp
+ sizeof(NameInfoResponse
),
853 if (ni_resp
->servlen
> 0) {
854 q
->serv
= strndup((const char*) ni_resp
+ sizeof(NameInfoResponse
) + ni_resp
->hostlen
,
864 return complete_query(resolve
, q
);
872 _public_
int sd_resolve_process(sd_resolve
*resolve
) {
873 RESOLVE_DONT_DESTROY(resolve
);
877 uint8_t space
[BUFSIZE
];
882 assert_return(resolve
, -EINVAL
);
883 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
885 /* We don't allow recursively invoking sd_resolve_process(). */
886 assert_return(!resolve
->current
, -EBUSY
);
888 l
= recv(resolve
->fds
[RESPONSE_RECV_FD
], &buf
, sizeof(buf
), 0);
896 return -ECONNREFUSED
;
898 r
= handle_response(resolve
, &buf
.packet
, (size_t) l
);
905 _public_
int sd_resolve_wait(sd_resolve
*resolve
, uint64_t timeout_usec
) {
908 assert_return(resolve
, -EINVAL
);
909 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
911 if (resolve
->n_done
>= resolve
->n_queries
)
915 r
= fd_wait_for_event(resolve
->fds
[RESPONSE_RECV_FD
], POLLIN
, timeout_usec
);
916 } while (r
== -EINTR
);
923 return sd_resolve_process(resolve
);
926 static int alloc_query(sd_resolve
*resolve
, bool floating
, sd_resolve_query
**_q
) {
933 if (resolve
->n_queries
>= QUERIES_MAX
)
936 r
= start_threads(resolve
, 1);
940 while (resolve
->query_array
[resolve
->current_id
% QUERIES_MAX
])
941 resolve
->current_id
++;
943 q
= resolve
->query_array
[resolve
->current_id
% QUERIES_MAX
] = new0(sd_resolve_query
, 1);
948 q
->resolve
= resolve
;
949 q
->floating
= floating
;
950 q
->id
= resolve
->current_id
++;
953 sd_resolve_ref(resolve
);
955 LIST_PREPEND(queries
, resolve
->queries
, q
);
956 resolve
->n_queries
++;
962 _public_
int sd_resolve_getaddrinfo(
964 sd_resolve_query
**_q
,
965 const char *node
, const char *service
,
966 const struct addrinfo
*hints
,
967 sd_resolve_getaddrinfo_handler_t callback
, void *userdata
) {
969 AddrInfoRequest req
= {};
970 struct msghdr mh
= {};
975 assert_return(resolve
, -EINVAL
);
976 assert_return(node
|| service
, -EINVAL
);
977 assert_return(callback
, -EINVAL
);
978 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
980 r
= alloc_query(resolve
, !_q
, &q
);
984 q
->type
= REQUEST_ADDRINFO
;
985 q
->getaddrinfo_handler
= callback
;
986 q
->userdata
= userdata
;
988 req
.node_len
= node
? strlen(node
)+1 : 0;
989 req
.service_len
= service
? strlen(service
)+1 : 0;
991 req
.header
.id
= q
->id
;
992 req
.header
.type
= REQUEST_ADDRINFO
;
993 req
.header
.length
= sizeof(AddrInfoRequest
) + req
.node_len
+ req
.service_len
;
996 req
.hints_valid
= true;
997 req
.ai_flags
= hints
->ai_flags
;
998 req
.ai_family
= hints
->ai_family
;
999 req
.ai_socktype
= hints
->ai_socktype
;
1000 req
.ai_protocol
= hints
->ai_protocol
;
1003 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= &req
, .iov_len
= sizeof(AddrInfoRequest
) };
1005 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= (void*) node
, .iov_len
= req
.node_len
};
1007 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= (void*) service
, .iov_len
= req
.service_len
};
1010 if (sendmsg(resolve
->fds
[REQUEST_SEND_FD
], &mh
, MSG_NOSIGNAL
) < 0) {
1011 sd_resolve_query_unref(q
);
1015 resolve
->n_outstanding
++;
1023 static int getaddrinfo_done(sd_resolve_query
* q
) {
1026 assert(q
->getaddrinfo_handler
);
1029 h_errno
= q
->_h_errno
;
1031 return q
->getaddrinfo_handler(q
, q
->ret
, q
->addrinfo
, q
->userdata
);
1034 _public_
int sd_resolve_getnameinfo(
1035 sd_resolve
*resolve
,
1036 sd_resolve_query
**_q
,
1037 const struct sockaddr
*sa
, socklen_t salen
,
1040 sd_resolve_getnameinfo_handler_t callback
,
1043 NameInfoRequest req
= {};
1044 struct msghdr mh
= {};
1045 struct iovec iov
[2];
1046 sd_resolve_query
*q
;
1049 assert_return(resolve
, -EINVAL
);
1050 assert_return(sa
, -EINVAL
);
1051 assert_return(salen
>= sizeof(struct sockaddr
), -EINVAL
);
1052 assert_return(salen
<= sizeof(union sockaddr_union
), -EINVAL
);
1053 assert_return((get
& ~SD_RESOLVE_GET_BOTH
) == 0, -EINVAL
);
1054 assert_return(callback
, -EINVAL
);
1055 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
1057 r
= alloc_query(resolve
, !_q
, &q
);
1061 q
->type
= REQUEST_NAMEINFO
;
1062 q
->getnameinfo_handler
= callback
;
1063 q
->userdata
= userdata
;
1065 req
.header
.id
= q
->id
;
1066 req
.header
.type
= REQUEST_NAMEINFO
;
1067 req
.header
.length
= sizeof(NameInfoRequest
) + salen
;
1070 req
.sockaddr_len
= salen
;
1071 req
.gethost
= !!(get
& SD_RESOLVE_GET_HOST
);
1072 req
.getserv
= !!(get
& SD_RESOLVE_GET_SERVICE
);
1074 iov
[0] = (struct iovec
) { .iov_base
= &req
, .iov_len
= sizeof(NameInfoRequest
) };
1075 iov
[1] = (struct iovec
) { .iov_base
= (void*) sa
, .iov_len
= salen
};
1080 if (sendmsg(resolve
->fds
[REQUEST_SEND_FD
], &mh
, MSG_NOSIGNAL
) < 0) {
1081 sd_resolve_query_unref(q
);
1085 resolve
->n_outstanding
++;
1093 static int getnameinfo_done(sd_resolve_query
*q
) {
1097 assert(q
->getnameinfo_handler
);
1100 h_errno
= q
->_h_errno
;
1102 return q
->getnameinfo_handler(q
, q
->ret
, q
->host
, q
->serv
, q
->userdata
);
1105 _public_ sd_resolve_query
* sd_resolve_query_ref(sd_resolve_query
*q
) {
1106 assert_return(q
, NULL
);
1108 assert(q
->n_ref
>= 1);
1114 static void resolve_freeaddrinfo(struct addrinfo
*ai
) {
1116 struct addrinfo
*next
= ai
->ai_next
;
1119 free(ai
->ai_canonname
);
1125 static void resolve_query_disconnect(sd_resolve_query
*q
) {
1126 sd_resolve
*resolve
;
1134 resolve
= q
->resolve
;
1135 assert(resolve
->n_queries
> 0);
1138 assert(resolve
->n_done
> 0);
1142 i
= q
->id
% QUERIES_MAX
;
1143 assert(resolve
->query_array
[i
] == q
);
1144 resolve
->query_array
[i
] = NULL
;
1145 LIST_REMOVE(queries
, resolve
->queries
, q
);
1146 resolve
->n_queries
--;
1150 sd_resolve_unref(resolve
);
1153 static void resolve_query_free(sd_resolve_query
*q
) {
1156 resolve_query_disconnect(q
);
1158 resolve_freeaddrinfo(q
->addrinfo
);
1164 _public_ sd_resolve_query
* sd_resolve_query_unref(sd_resolve_query
* q
) {
1168 assert(q
->n_ref
>= 1);
1172 resolve_query_free(q
);
1177 _public_
int sd_resolve_query_is_done(sd_resolve_query
*q
) {
1178 assert_return(q
, -EINVAL
);
1179 assert_return(!resolve_pid_changed(q
->resolve
), -ECHILD
);
1184 _public_
void* sd_resolve_query_set_userdata(sd_resolve_query
*q
, void *userdata
) {
1187 assert_return(q
, NULL
);
1188 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1191 q
->userdata
= userdata
;
1196 _public_
void* sd_resolve_query_get_userdata(sd_resolve_query
*q
) {
1197 assert_return(q
, NULL
);
1198 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1203 _public_ sd_resolve
*sd_resolve_query_get_resolve(sd_resolve_query
*q
) {
1204 assert_return(q
, NULL
);
1205 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1210 static int io_callback(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
1211 sd_resolve
*resolve
= userdata
;
1216 r
= sd_resolve_process(resolve
);
1223 _public_
int sd_resolve_attach_event(sd_resolve
*resolve
, sd_event
*event
, int64_t priority
) {
1226 assert_return(resolve
, -EINVAL
);
1227 assert_return(!resolve
->event
, -EBUSY
);
1229 assert(!resolve
->event_source
);
1232 resolve
->event
= sd_event_ref(event
);
1234 r
= sd_event_default(&resolve
->event
);
1239 r
= sd_event_add_io(resolve
->event
, &resolve
->event_source
, resolve
->fds
[RESPONSE_RECV_FD
], POLLIN
, io_callback
, resolve
);
1243 r
= sd_event_source_set_priority(resolve
->event_source
, priority
);
1250 sd_resolve_detach_event(resolve
);
1254 _public_
int sd_resolve_detach_event(sd_resolve
*resolve
) {
1255 assert_return(resolve
, -EINVAL
);
1257 if (!resolve
->event
)
1260 if (resolve
->event_source
) {
1261 sd_event_source_set_enabled(resolve
->event_source
, SD_EVENT_OFF
);
1262 resolve
->event_source
= sd_event_source_unref(resolve
->event_source
);
1265 resolve
->event
= sd_event_unref(resolve
->event
);
1269 _public_ sd_event
*sd_resolve_get_event(sd_resolve
*resolve
) {
1270 assert_return(resolve
, NULL
);
1272 return resolve
->event
;