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 for (i
= 0; i
< _FD_MAX
; i
++)
511 resolve
->fds
[i
] = fd_move_above_stdio(resolve
->fds
[i
]);
513 (void) fd_inc_sndbuf(resolve
->fds
[REQUEST_SEND_FD
], QUERIES_MAX
* BUFSIZE
);
514 (void) fd_inc_rcvbuf(resolve
->fds
[REQUEST_RECV_FD
], QUERIES_MAX
* BUFSIZE
);
515 (void) fd_inc_sndbuf(resolve
->fds
[RESPONSE_SEND_FD
], QUERIES_MAX
* BUFSIZE
);
516 (void) fd_inc_rcvbuf(resolve
->fds
[RESPONSE_RECV_FD
], QUERIES_MAX
* BUFSIZE
);
518 (void) fd_nonblock(resolve
->fds
[RESPONSE_RECV_FD
], true);
524 sd_resolve_unref(resolve
);
528 _public_
int sd_resolve_default(sd_resolve
**ret
) {
530 static thread_local sd_resolve
*default_resolve
= NULL
;
531 sd_resolve
*e
= NULL
;
535 return !!default_resolve
;
537 if (default_resolve
) {
538 *ret
= sd_resolve_ref(default_resolve
);
542 r
= sd_resolve_new(&e
);
546 e
->default_resolve_ptr
= &default_resolve
;
554 _public_
int sd_resolve_get_tid(sd_resolve
*resolve
, pid_t
*tid
) {
555 assert_return(resolve
, -EINVAL
);
556 assert_return(tid
, -EINVAL
);
557 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
559 if (resolve
->tid
!= 0) {
565 return sd_event_get_tid(resolve
->event
, tid
);
570 static void resolve_free(sd_resolve
*resolve
) {
577 while ((q
= resolve
->queries
)) {
579 resolve_query_disconnect(q
);
580 sd_resolve_query_unref(q
);
583 if (resolve
->default_resolve_ptr
)
584 *(resolve
->default_resolve_ptr
) = NULL
;
586 resolve
->dead
= true;
588 sd_resolve_detach_event(resolve
);
590 if (resolve
->fds
[REQUEST_SEND_FD
] >= 0) {
593 .type
= REQUEST_TERMINATE
,
594 .length
= sizeof(req
)
597 /* Send one termination packet for each worker */
598 for (i
= 0; i
< resolve
->n_valid_workers
; i
++)
599 (void) send(resolve
->fds
[REQUEST_SEND_FD
], &req
, req
.length
, MSG_NOSIGNAL
);
602 /* Now terminate them and wait until they are gone.
603 If we get an error than most likely the thread already exited. */
604 for (i
= 0; i
< resolve
->n_valid_workers
; i
++)
605 (void) pthread_join(resolve
->workers
[i
], NULL
);
607 /* Close all communication channels */
608 close_many(resolve
->fds
, _FD_MAX
);
612 _public_ sd_resolve
* sd_resolve_ref(sd_resolve
*resolve
) {
613 assert_return(resolve
, NULL
);
615 assert(resolve
->n_ref
>= 1);
621 _public_ sd_resolve
* sd_resolve_unref(sd_resolve
*resolve
) {
626 assert(resolve
->n_ref
>= 1);
629 if (resolve
->n_ref
<= 0)
630 resolve_free(resolve
);
635 _public_
int sd_resolve_get_fd(sd_resolve
*resolve
) {
636 assert_return(resolve
, -EINVAL
);
637 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
639 return resolve
->fds
[RESPONSE_RECV_FD
];
642 _public_
int sd_resolve_get_events(sd_resolve
*resolve
) {
643 assert_return(resolve
, -EINVAL
);
644 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
646 return resolve
->n_queries
> resolve
->n_done
? POLLIN
: 0;
649 _public_
int sd_resolve_get_timeout(sd_resolve
*resolve
, uint64_t *usec
) {
650 assert_return(resolve
, -EINVAL
);
651 assert_return(usec
, -EINVAL
);
652 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
654 *usec
= (uint64_t) -1;
658 static sd_resolve_query
*lookup_query(sd_resolve
*resolve
, unsigned id
) {
663 q
= resolve
->query_array
[id
% QUERIES_MAX
];
671 static int complete_query(sd_resolve
*resolve
, sd_resolve_query
*q
) {
676 assert(q
->resolve
== resolve
);
681 resolve
->current
= sd_resolve_query_ref(q
);
685 case REQUEST_ADDRINFO
:
686 r
= getaddrinfo_done(q
);
689 case REQUEST_NAMEINFO
:
690 r
= getnameinfo_done(q
);
694 assert_not_reached("Cannot complete unknown query type");
697 resolve
->current
= NULL
;
700 resolve_query_disconnect(q
);
701 sd_resolve_query_unref(q
);
704 sd_resolve_query_unref(q
);
709 static int unserialize_addrinfo(const void **p
, size_t *length
, struct addrinfo
**ret_ai
) {
710 AddrInfoSerialization s
;
719 if (*length
< sizeof(AddrInfoSerialization
))
722 memcpy(&s
, *p
, sizeof(s
));
724 l
= sizeof(AddrInfoSerialization
) + s
.ai_addrlen
+ s
.canonname_len
;
728 ai
= new0(struct addrinfo
, 1);
732 ai
->ai_flags
= s
.ai_flags
;
733 ai
->ai_family
= s
.ai_family
;
734 ai
->ai_socktype
= s
.ai_socktype
;
735 ai
->ai_protocol
= s
.ai_protocol
;
736 ai
->ai_addrlen
= s
.ai_addrlen
;
738 if (s
.ai_addrlen
> 0) {
739 ai
->ai_addr
= memdup((const uint8_t*) *p
+ sizeof(AddrInfoSerialization
), s
.ai_addrlen
);
746 if (s
.canonname_len
> 0) {
747 ai
->ai_canonname
= memdup((const uint8_t*) *p
+ sizeof(AddrInfoSerialization
) + s
.ai_addrlen
, s
.canonname_len
);
748 if (!ai
->ai_canonname
) {
757 *p
= ((const uint8_t*) *p
) + l
;
762 static int handle_response(sd_resolve
*resolve
, const Packet
*packet
, size_t length
) {
769 resp
= &packet
->rheader
;
771 assert(length
>= sizeof(RHeader
));
772 assert(length
== resp
->length
);
774 if (resp
->type
== RESPONSE_DIED
) {
775 resolve
->dead
= true;
779 assert(resolve
->n_outstanding
> 0);
780 resolve
->n_outstanding
--;
782 q
= lookup_query(resolve
, resp
->id
);
786 switch (resp
->type
) {
788 case RESPONSE_ADDRINFO
: {
789 const AddrInfoResponse
*ai_resp
= &packet
->addrinfo_response
;
792 struct addrinfo
*prev
= NULL
;
794 assert(length
>= sizeof(AddrInfoResponse
));
795 assert(q
->type
== REQUEST_ADDRINFO
);
797 q
->ret
= ai_resp
->ret
;
798 q
->_errno
= ai_resp
->_errno
;
799 q
->_h_errno
= ai_resp
->_h_errno
;
801 l
= length
- sizeof(AddrInfoResponse
);
802 p
= (const uint8_t*) resp
+ sizeof(AddrInfoResponse
);
805 struct addrinfo
*ai
= NULL
;
807 r
= unserialize_addrinfo(&p
, &l
, &ai
);
812 freeaddrinfo(q
->addrinfo
);
825 return complete_query(resolve
, q
);
828 case RESPONSE_NAMEINFO
: {
829 const NameInfoResponse
*ni_resp
= &packet
->nameinfo_response
;
831 assert(length
>= sizeof(NameInfoResponse
));
832 assert(q
->type
== REQUEST_NAMEINFO
);
834 if (ni_resp
->hostlen
> DNS_HOSTNAME_MAX
||
835 ni_resp
->servlen
> DNS_HOSTNAME_MAX
||
836 sizeof(NameInfoResponse
) + ni_resp
->hostlen
+ ni_resp
->servlen
> length
+ 2) {
842 q
->ret
= ni_resp
->ret
;
843 q
->_errno
= ni_resp
->_errno
;
844 q
->_h_errno
= ni_resp
->_h_errno
;
846 if (ni_resp
->hostlen
> 0) {
847 q
->host
= strndup((const char*) ni_resp
+ sizeof(NameInfoResponse
),
856 if (ni_resp
->servlen
> 0) {
857 q
->serv
= strndup((const char*) ni_resp
+ sizeof(NameInfoResponse
) + ni_resp
->hostlen
,
867 return complete_query(resolve
, q
);
875 _public_
int sd_resolve_process(sd_resolve
*resolve
) {
876 RESOLVE_DONT_DESTROY(resolve
);
880 uint8_t space
[BUFSIZE
];
885 assert_return(resolve
, -EINVAL
);
886 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
888 /* We don't allow recursively invoking sd_resolve_process(). */
889 assert_return(!resolve
->current
, -EBUSY
);
891 l
= recv(resolve
->fds
[RESPONSE_RECV_FD
], &buf
, sizeof(buf
), 0);
899 return -ECONNREFUSED
;
901 r
= handle_response(resolve
, &buf
.packet
, (size_t) l
);
908 _public_
int sd_resolve_wait(sd_resolve
*resolve
, uint64_t timeout_usec
) {
911 assert_return(resolve
, -EINVAL
);
912 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
914 if (resolve
->n_done
>= resolve
->n_queries
)
918 r
= fd_wait_for_event(resolve
->fds
[RESPONSE_RECV_FD
], POLLIN
, timeout_usec
);
919 } while (r
== -EINTR
);
926 return sd_resolve_process(resolve
);
929 static int alloc_query(sd_resolve
*resolve
, bool floating
, sd_resolve_query
**_q
) {
936 if (resolve
->n_queries
>= QUERIES_MAX
)
939 r
= start_threads(resolve
, 1);
943 while (resolve
->query_array
[resolve
->current_id
% QUERIES_MAX
])
944 resolve
->current_id
++;
946 q
= resolve
->query_array
[resolve
->current_id
% QUERIES_MAX
] = new0(sd_resolve_query
, 1);
951 q
->resolve
= resolve
;
952 q
->floating
= floating
;
953 q
->id
= resolve
->current_id
++;
956 sd_resolve_ref(resolve
);
958 LIST_PREPEND(queries
, resolve
->queries
, q
);
959 resolve
->n_queries
++;
965 _public_
int sd_resolve_getaddrinfo(
967 sd_resolve_query
**_q
,
968 const char *node
, const char *service
,
969 const struct addrinfo
*hints
,
970 sd_resolve_getaddrinfo_handler_t callback
, void *userdata
) {
972 AddrInfoRequest req
= {};
973 struct msghdr mh
= {};
978 assert_return(resolve
, -EINVAL
);
979 assert_return(node
|| service
, -EINVAL
);
980 assert_return(callback
, -EINVAL
);
981 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
983 r
= alloc_query(resolve
, !_q
, &q
);
987 q
->type
= REQUEST_ADDRINFO
;
988 q
->getaddrinfo_handler
= callback
;
989 q
->userdata
= userdata
;
991 req
.node_len
= node
? strlen(node
)+1 : 0;
992 req
.service_len
= service
? strlen(service
)+1 : 0;
994 req
.header
.id
= q
->id
;
995 req
.header
.type
= REQUEST_ADDRINFO
;
996 req
.header
.length
= sizeof(AddrInfoRequest
) + req
.node_len
+ req
.service_len
;
999 req
.hints_valid
= true;
1000 req
.ai_flags
= hints
->ai_flags
;
1001 req
.ai_family
= hints
->ai_family
;
1002 req
.ai_socktype
= hints
->ai_socktype
;
1003 req
.ai_protocol
= hints
->ai_protocol
;
1006 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= &req
, .iov_len
= sizeof(AddrInfoRequest
) };
1008 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= (void*) node
, .iov_len
= req
.node_len
};
1010 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= (void*) service
, .iov_len
= req
.service_len
};
1013 if (sendmsg(resolve
->fds
[REQUEST_SEND_FD
], &mh
, MSG_NOSIGNAL
) < 0) {
1014 sd_resolve_query_unref(q
);
1018 resolve
->n_outstanding
++;
1026 static int getaddrinfo_done(sd_resolve_query
* q
) {
1029 assert(q
->getaddrinfo_handler
);
1032 h_errno
= q
->_h_errno
;
1034 return q
->getaddrinfo_handler(q
, q
->ret
, q
->addrinfo
, q
->userdata
);
1037 _public_
int sd_resolve_getnameinfo(
1038 sd_resolve
*resolve
,
1039 sd_resolve_query
**_q
,
1040 const struct sockaddr
*sa
, socklen_t salen
,
1043 sd_resolve_getnameinfo_handler_t callback
,
1046 NameInfoRequest req
= {};
1047 struct msghdr mh
= {};
1048 struct iovec iov
[2];
1049 sd_resolve_query
*q
;
1052 assert_return(resolve
, -EINVAL
);
1053 assert_return(sa
, -EINVAL
);
1054 assert_return(salen
>= sizeof(struct sockaddr
), -EINVAL
);
1055 assert_return(salen
<= sizeof(union sockaddr_union
), -EINVAL
);
1056 assert_return((get
& ~SD_RESOLVE_GET_BOTH
) == 0, -EINVAL
);
1057 assert_return(callback
, -EINVAL
);
1058 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
1060 r
= alloc_query(resolve
, !_q
, &q
);
1064 q
->type
= REQUEST_NAMEINFO
;
1065 q
->getnameinfo_handler
= callback
;
1066 q
->userdata
= userdata
;
1068 req
.header
.id
= q
->id
;
1069 req
.header
.type
= REQUEST_NAMEINFO
;
1070 req
.header
.length
= sizeof(NameInfoRequest
) + salen
;
1073 req
.sockaddr_len
= salen
;
1074 req
.gethost
= !!(get
& SD_RESOLVE_GET_HOST
);
1075 req
.getserv
= !!(get
& SD_RESOLVE_GET_SERVICE
);
1077 iov
[0] = (struct iovec
) { .iov_base
= &req
, .iov_len
= sizeof(NameInfoRequest
) };
1078 iov
[1] = (struct iovec
) { .iov_base
= (void*) sa
, .iov_len
= salen
};
1083 if (sendmsg(resolve
->fds
[REQUEST_SEND_FD
], &mh
, MSG_NOSIGNAL
) < 0) {
1084 sd_resolve_query_unref(q
);
1088 resolve
->n_outstanding
++;
1096 static int getnameinfo_done(sd_resolve_query
*q
) {
1100 assert(q
->getnameinfo_handler
);
1103 h_errno
= q
->_h_errno
;
1105 return q
->getnameinfo_handler(q
, q
->ret
, q
->host
, q
->serv
, q
->userdata
);
1108 _public_ sd_resolve_query
* sd_resolve_query_ref(sd_resolve_query
*q
) {
1109 assert_return(q
, NULL
);
1111 assert(q
->n_ref
>= 1);
1117 static void resolve_freeaddrinfo(struct addrinfo
*ai
) {
1119 struct addrinfo
*next
= ai
->ai_next
;
1122 free(ai
->ai_canonname
);
1128 static void resolve_query_disconnect(sd_resolve_query
*q
) {
1129 sd_resolve
*resolve
;
1137 resolve
= q
->resolve
;
1138 assert(resolve
->n_queries
> 0);
1141 assert(resolve
->n_done
> 0);
1145 i
= q
->id
% QUERIES_MAX
;
1146 assert(resolve
->query_array
[i
] == q
);
1147 resolve
->query_array
[i
] = NULL
;
1148 LIST_REMOVE(queries
, resolve
->queries
, q
);
1149 resolve
->n_queries
--;
1153 sd_resolve_unref(resolve
);
1156 static void resolve_query_free(sd_resolve_query
*q
) {
1159 resolve_query_disconnect(q
);
1161 resolve_freeaddrinfo(q
->addrinfo
);
1167 _public_ sd_resolve_query
* sd_resolve_query_unref(sd_resolve_query
* q
) {
1171 assert(q
->n_ref
>= 1);
1175 resolve_query_free(q
);
1180 _public_
int sd_resolve_query_is_done(sd_resolve_query
*q
) {
1181 assert_return(q
, -EINVAL
);
1182 assert_return(!resolve_pid_changed(q
->resolve
), -ECHILD
);
1187 _public_
void* sd_resolve_query_set_userdata(sd_resolve_query
*q
, void *userdata
) {
1190 assert_return(q
, NULL
);
1191 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1194 q
->userdata
= userdata
;
1199 _public_
void* sd_resolve_query_get_userdata(sd_resolve_query
*q
) {
1200 assert_return(q
, NULL
);
1201 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1206 _public_ sd_resolve
*sd_resolve_query_get_resolve(sd_resolve_query
*q
) {
1207 assert_return(q
, NULL
);
1208 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1213 static int io_callback(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
1214 sd_resolve
*resolve
= userdata
;
1219 r
= sd_resolve_process(resolve
);
1226 _public_
int sd_resolve_attach_event(sd_resolve
*resolve
, sd_event
*event
, int64_t priority
) {
1229 assert_return(resolve
, -EINVAL
);
1230 assert_return(!resolve
->event
, -EBUSY
);
1232 assert(!resolve
->event_source
);
1235 resolve
->event
= sd_event_ref(event
);
1237 r
= sd_event_default(&resolve
->event
);
1242 r
= sd_event_add_io(resolve
->event
, &resolve
->event_source
, resolve
->fds
[RESPONSE_RECV_FD
], POLLIN
, io_callback
, resolve
);
1246 r
= sd_event_source_set_priority(resolve
->event_source
, priority
);
1253 sd_resolve_detach_event(resolve
);
1257 _public_
int sd_resolve_detach_event(sd_resolve
*resolve
) {
1258 assert_return(resolve
, -EINVAL
);
1260 if (!resolve
->event
)
1263 if (resolve
->event_source
) {
1264 sd_event_source_set_enabled(resolve
->event_source
, SD_EVENT_OFF
);
1265 resolve
->event_source
= sd_event_source_unref(resolve
->event_source
);
1268 resolve
->event
= sd_event_unref(resolve
->event
);
1272 _public_ sd_event
*sd_resolve_get_event(sd_resolve
*resolve
) {
1273 assert_return(resolve
, NULL
);
1275 return resolve
->event
;