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"
40 #include "socket-util.h"
43 #define WORKERS_MIN 1U
44 #define WORKERS_MAX 16U
45 #define QUERIES_MAX 256U
46 #define BUFSIZE 10240U
73 pthread_t workers
[WORKERS_MAX
];
74 unsigned n_valid_workers
;
77 sd_resolve_query
* query_array
[QUERIES_MAX
];
78 unsigned n_queries
, n_done
, n_outstanding
;
80 sd_event_source
*event_source
;
83 sd_resolve_query
*current
;
85 sd_resolve
**default_resolve_ptr
;
88 LIST_HEAD(sd_resolve_query
, queries
);
91 struct sd_resolve_query
{
104 struct addrinfo
*addrinfo
;
108 sd_resolve_getaddrinfo_handler_t getaddrinfo_handler
;
109 sd_resolve_getnameinfo_handler_t getnameinfo_handler
;
114 LIST_FIELDS(sd_resolve_query
, queries
);
117 typedef struct RHeader
{
123 typedef struct AddrInfoRequest
{
124 struct RHeader header
;
130 size_t node_len
, service_len
;
133 typedef struct AddrInfoResponse
{
134 struct RHeader header
;
138 /* followed by addrinfo_serialization[] */
141 typedef struct AddrInfoSerialization
{
147 size_t canonname_len
;
148 /* Followed by ai_addr amd ai_canonname with variable lengths */
149 } AddrInfoSerialization
;
151 typedef struct NameInfoRequest
{
152 struct RHeader header
;
154 socklen_t sockaddr_len
;
155 bool gethost
:1, getserv
:1;
158 typedef struct NameInfoResponse
{
159 struct RHeader header
;
160 size_t hostlen
, servlen
;
166 typedef union Packet
{
168 AddrInfoRequest addrinfo_request
;
169 AddrInfoResponse addrinfo_response
;
170 NameInfoRequest nameinfo_request
;
171 NameInfoResponse nameinfo_response
;
174 static int getaddrinfo_done(sd_resolve_query
* q
);
175 static int getnameinfo_done(sd_resolve_query
*q
);
177 static void resolve_query_disconnect(sd_resolve_query
*q
);
179 #define RESOLVE_DONT_DESTROY(resolve) \
180 _cleanup_(sd_resolve_unrefp) _unused_ sd_resolve *_dont_destroy_##resolve = sd_resolve_ref(resolve)
182 static int send_died(int out_fd
) {
185 .type
= RESPONSE_DIED
,
186 .length
= sizeof(RHeader
),
191 if (send(out_fd
, &rh
, rh
.length
, MSG_NOSIGNAL
) < 0)
197 static void *serialize_addrinfo(void *p
, const struct addrinfo
*ai
, size_t *length
, size_t maxlength
) {
198 AddrInfoSerialization s
;
204 assert(*length
<= maxlength
);
206 cnl
= ai
->ai_canonname
? strlen(ai
->ai_canonname
)+1 : 0;
207 l
= sizeof(AddrInfoSerialization
) + ai
->ai_addrlen
+ cnl
;
209 if (*length
+ l
> maxlength
)
212 s
.ai_flags
= ai
->ai_flags
;
213 s
.ai_family
= ai
->ai_family
;
214 s
.ai_socktype
= ai
->ai_socktype
;
215 s
.ai_protocol
= ai
->ai_protocol
;
216 s
.ai_addrlen
= ai
->ai_addrlen
;
217 s
.canonname_len
= cnl
;
219 memcpy((uint8_t*) p
, &s
, sizeof(AddrInfoSerialization
));
220 memcpy((uint8_t*) p
+ sizeof(AddrInfoSerialization
), ai
->ai_addr
, ai
->ai_addrlen
);
221 memcpy_safe((char*) p
+ sizeof(AddrInfoSerialization
) + ai
->ai_addrlen
,
222 ai
->ai_canonname
, cnl
);
225 return (uint8_t*) p
+ l
;
228 static int send_addrinfo_reply(
236 AddrInfoResponse resp
= {
237 .header
.type
= RESPONSE_ADDRINFO
,
239 .header
.length
= sizeof(AddrInfoResponse
),
242 ._h_errno
= _h_errno
,
245 struct msghdr mh
= {};
248 AddrInfoSerialization ais
;
249 uint8_t space
[BUFSIZE
];
254 if (ret
== 0 && ai
) {
258 for (k
= ai
; k
; k
= k
->ai_next
) {
259 p
= serialize_addrinfo(p
, k
, &resp
.header
.length
, (uint8_t*) &buffer
+ BUFSIZE
- (uint8_t*) p
);
270 iov
[0] = (struct iovec
) { .iov_base
= &resp
, .iov_len
= sizeof(AddrInfoResponse
) };
271 iov
[1] = (struct iovec
) { .iov_base
= &buffer
, .iov_len
= resp
.header
.length
- sizeof(AddrInfoResponse
) };
274 mh
.msg_iovlen
= ELEMENTSOF(iov
);
276 if (sendmsg(out_fd
, &mh
, MSG_NOSIGNAL
) < 0)
282 static int send_nameinfo_reply(
291 NameInfoResponse resp
= {
292 .header
.type
= RESPONSE_NAMEINFO
,
296 ._h_errno
= _h_errno
,
299 struct msghdr mh
= {};
305 sl
= serv
? strlen(serv
)+1 : 0;
306 hl
= host
? strlen(host
)+1 : 0;
308 resp
.header
.length
= sizeof(NameInfoResponse
) + hl
+ sl
;
312 iov
[0] = (struct iovec
) { .iov_base
= &resp
, .iov_len
= sizeof(NameInfoResponse
) };
313 iov
[1] = (struct iovec
) { .iov_base
= (void*) host
, .iov_len
= hl
};
314 iov
[2] = (struct iovec
) { .iov_base
= (void*) serv
, .iov_len
= sl
};
317 mh
.msg_iovlen
= ELEMENTSOF(iov
);
319 if (sendmsg(out_fd
, &mh
, MSG_NOSIGNAL
) < 0)
325 static int handle_request(int out_fd
, const Packet
*packet
, size_t length
) {
331 req
= &packet
->rheader
;
333 assert(length
>= sizeof(RHeader
));
334 assert(length
== req
->length
);
338 case REQUEST_ADDRINFO
: {
339 const AddrInfoRequest
*ai_req
= &packet
->addrinfo_request
;
340 struct addrinfo hints
= {}, *result
= NULL
;
341 const char *node
, *service
;
344 assert(length
>= sizeof(AddrInfoRequest
));
345 assert(length
== sizeof(AddrInfoRequest
) + ai_req
->node_len
+ ai_req
->service_len
);
347 hints
.ai_flags
= ai_req
->ai_flags
;
348 hints
.ai_family
= ai_req
->ai_family
;
349 hints
.ai_socktype
= ai_req
->ai_socktype
;
350 hints
.ai_protocol
= ai_req
->ai_protocol
;
352 node
= ai_req
->node_len
? (const char*) ai_req
+ sizeof(AddrInfoRequest
) : NULL
;
353 service
= ai_req
->service_len
? (const char*) ai_req
+ sizeof(AddrInfoRequest
) + ai_req
->node_len
: NULL
;
357 ai_req
->hints_valid
? &hints
: NULL
,
360 /* send_addrinfo_reply() frees result */
361 return send_addrinfo_reply(out_fd
, req
->id
, ret
, result
, errno
, h_errno
);
364 case REQUEST_NAMEINFO
: {
365 const NameInfoRequest
*ni_req
= &packet
->nameinfo_request
;
366 char hostbuf
[NI_MAXHOST
], servbuf
[NI_MAXSERV
];
367 union sockaddr_union sa
;
370 assert(length
>= sizeof(NameInfoRequest
));
371 assert(length
== sizeof(NameInfoRequest
) + ni_req
->sockaddr_len
);
372 assert(sizeof(sa
) >= ni_req
->sockaddr_len
);
374 memcpy(&sa
, (const uint8_t *) ni_req
+ sizeof(NameInfoRequest
), ni_req
->sockaddr_len
);
376 ret
= getnameinfo(&sa
.sa
, ni_req
->sockaddr_len
,
377 ni_req
->gethost
? hostbuf
: NULL
, ni_req
->gethost
? sizeof(hostbuf
) : 0,
378 ni_req
->getserv
? servbuf
: NULL
, ni_req
->getserv
? sizeof(servbuf
) : 0,
381 return send_nameinfo_reply(out_fd
, req
->id
, ret
,
382 ret
== 0 && ni_req
->gethost
? hostbuf
: NULL
,
383 ret
== 0 && ni_req
->getserv
? servbuf
: NULL
,
387 case REQUEST_TERMINATE
:
392 assert_not_reached("Unknown request");
398 static void* thread_worker(void *p
) {
399 sd_resolve
*resolve
= p
;
402 /* No signals in this thread please */
403 assert_se(sigfillset(&fullset
) == 0);
404 assert_se(pthread_sigmask(SIG_BLOCK
, &fullset
, NULL
) == 0);
406 /* Assign a pretty name to this thread */
407 (void) prctl(PR_SET_NAME
, (unsigned long) "sd-resolve");
409 while (!resolve
->dead
) {
412 uint8_t space
[BUFSIZE
];
416 length
= recv(resolve
->fds
[REQUEST_RECV_FD
], &buf
, sizeof(buf
), 0);
429 if (handle_request(resolve
->fds
[RESPONSE_SEND_FD
], &buf
.packet
, (size_t) length
) < 0)
433 send_died(resolve
->fds
[RESPONSE_SEND_FD
]);
438 static int start_threads(sd_resolve
*resolve
, unsigned extra
) {
442 n
= resolve
->n_outstanding
+ extra
;
443 n
= CLAMP(n
, WORKERS_MIN
, WORKERS_MAX
);
445 while (resolve
->n_valid_workers
< n
) {
447 r
= pthread_create(&resolve
->workers
[resolve
->n_valid_workers
], NULL
, thread_worker
, resolve
);
451 resolve
->n_valid_workers
++;
457 static bool resolve_pid_changed(sd_resolve
*r
) {
460 /* We don't support people creating a resolver and keeping it
461 * around after fork(). Let's complain. */
463 return r
->original_pid
!= getpid_cached();
466 _public_
int sd_resolve_new(sd_resolve
**ret
) {
467 sd_resolve
*resolve
= NULL
;
470 assert_return(ret
, -EINVAL
);
472 resolve
= new0(sd_resolve
, 1);
477 resolve
->original_pid
= getpid_cached();
479 for (i
= 0; i
< _FD_MAX
; i
++)
480 resolve
->fds
[i
] = -1;
482 r
= socketpair(PF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0, resolve
->fds
+ REQUEST_RECV_FD
);
488 r
= socketpair(PF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0, resolve
->fds
+ RESPONSE_RECV_FD
);
494 fd_inc_sndbuf(resolve
->fds
[REQUEST_SEND_FD
], QUERIES_MAX
* BUFSIZE
);
495 fd_inc_rcvbuf(resolve
->fds
[REQUEST_RECV_FD
], QUERIES_MAX
* BUFSIZE
);
496 fd_inc_sndbuf(resolve
->fds
[RESPONSE_SEND_FD
], QUERIES_MAX
* BUFSIZE
);
497 fd_inc_rcvbuf(resolve
->fds
[RESPONSE_RECV_FD
], QUERIES_MAX
* BUFSIZE
);
499 fd_nonblock(resolve
->fds
[RESPONSE_RECV_FD
], true);
505 sd_resolve_unref(resolve
);
509 _public_
int sd_resolve_default(sd_resolve
**ret
) {
511 static thread_local sd_resolve
*default_resolve
= NULL
;
512 sd_resolve
*e
= NULL
;
516 return !!default_resolve
;
518 if (default_resolve
) {
519 *ret
= sd_resolve_ref(default_resolve
);
523 r
= sd_resolve_new(&e
);
527 e
->default_resolve_ptr
= &default_resolve
;
535 _public_
int sd_resolve_get_tid(sd_resolve
*resolve
, pid_t
*tid
) {
536 assert_return(resolve
, -EINVAL
);
537 assert_return(tid
, -EINVAL
);
538 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
540 if (resolve
->tid
!= 0) {
546 return sd_event_get_tid(resolve
->event
, tid
);
551 static void resolve_free(sd_resolve
*resolve
) {
558 while ((q
= resolve
->queries
)) {
560 resolve_query_disconnect(q
);
561 sd_resolve_query_unref(q
);
564 if (resolve
->default_resolve_ptr
)
565 *(resolve
->default_resolve_ptr
) = NULL
;
567 resolve
->dead
= true;
569 sd_resolve_detach_event(resolve
);
571 if (resolve
->fds
[REQUEST_SEND_FD
] >= 0) {
574 .type
= REQUEST_TERMINATE
,
575 .length
= sizeof(req
)
578 /* Send one termination packet for each worker */
579 for (i
= 0; i
< resolve
->n_valid_workers
; i
++)
580 (void) send(resolve
->fds
[REQUEST_SEND_FD
], &req
, req
.length
, MSG_NOSIGNAL
);
583 /* Now terminate them and wait until they are gone.
584 If we get an error than most likely the thread already exited. */
585 for (i
= 0; i
< resolve
->n_valid_workers
; i
++)
586 (void) pthread_join(resolve
->workers
[i
], NULL
);
588 /* Close all communication channels */
589 close_many(resolve
->fds
, _FD_MAX
);
593 _public_ sd_resolve
* sd_resolve_ref(sd_resolve
*resolve
) {
594 assert_return(resolve
, NULL
);
596 assert(resolve
->n_ref
>= 1);
602 _public_ sd_resolve
* sd_resolve_unref(sd_resolve
*resolve
) {
607 assert(resolve
->n_ref
>= 1);
610 if (resolve
->n_ref
<= 0)
611 resolve_free(resolve
);
616 _public_
int sd_resolve_get_fd(sd_resolve
*resolve
) {
617 assert_return(resolve
, -EINVAL
);
618 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
620 return resolve
->fds
[RESPONSE_RECV_FD
];
623 _public_
int sd_resolve_get_events(sd_resolve
*resolve
) {
624 assert_return(resolve
, -EINVAL
);
625 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
627 return resolve
->n_queries
> resolve
->n_done
? POLLIN
: 0;
630 _public_
int sd_resolve_get_timeout(sd_resolve
*resolve
, uint64_t *usec
) {
631 assert_return(resolve
, -EINVAL
);
632 assert_return(usec
, -EINVAL
);
633 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
635 *usec
= (uint64_t) -1;
639 static sd_resolve_query
*lookup_query(sd_resolve
*resolve
, unsigned id
) {
644 q
= resolve
->query_array
[id
% QUERIES_MAX
];
652 static int complete_query(sd_resolve
*resolve
, sd_resolve_query
*q
) {
657 assert(q
->resolve
== resolve
);
662 resolve
->current
= sd_resolve_query_ref(q
);
666 case REQUEST_ADDRINFO
:
667 r
= getaddrinfo_done(q
);
670 case REQUEST_NAMEINFO
:
671 r
= getnameinfo_done(q
);
675 assert_not_reached("Cannot complete unknown query type");
678 resolve
->current
= NULL
;
681 resolve_query_disconnect(q
);
682 sd_resolve_query_unref(q
);
685 sd_resolve_query_unref(q
);
690 static int unserialize_addrinfo(const void **p
, size_t *length
, struct addrinfo
**ret_ai
) {
691 AddrInfoSerialization s
;
700 if (*length
< sizeof(AddrInfoSerialization
))
703 memcpy(&s
, *p
, sizeof(s
));
705 l
= sizeof(AddrInfoSerialization
) + s
.ai_addrlen
+ s
.canonname_len
;
709 ai
= new0(struct addrinfo
, 1);
713 ai
->ai_flags
= s
.ai_flags
;
714 ai
->ai_family
= s
.ai_family
;
715 ai
->ai_socktype
= s
.ai_socktype
;
716 ai
->ai_protocol
= s
.ai_protocol
;
717 ai
->ai_addrlen
= s
.ai_addrlen
;
719 if (s
.ai_addrlen
> 0) {
720 ai
->ai_addr
= memdup((const uint8_t*) *p
+ sizeof(AddrInfoSerialization
), s
.ai_addrlen
);
727 if (s
.canonname_len
> 0) {
728 ai
->ai_canonname
= memdup((const uint8_t*) *p
+ sizeof(AddrInfoSerialization
) + s
.ai_addrlen
, s
.canonname_len
);
729 if (!ai
->ai_canonname
) {
738 *p
= ((const uint8_t*) *p
) + l
;
743 static int handle_response(sd_resolve
*resolve
, const Packet
*packet
, size_t length
) {
750 resp
= &packet
->rheader
;
752 assert(length
>= sizeof(RHeader
));
753 assert(length
== resp
->length
);
755 if (resp
->type
== RESPONSE_DIED
) {
756 resolve
->dead
= true;
760 assert(resolve
->n_outstanding
> 0);
761 resolve
->n_outstanding
--;
763 q
= lookup_query(resolve
, resp
->id
);
767 switch (resp
->type
) {
769 case RESPONSE_ADDRINFO
: {
770 const AddrInfoResponse
*ai_resp
= &packet
->addrinfo_response
;
773 struct addrinfo
*prev
= NULL
;
775 assert(length
>= sizeof(AddrInfoResponse
));
776 assert(q
->type
== REQUEST_ADDRINFO
);
778 q
->ret
= ai_resp
->ret
;
779 q
->_errno
= ai_resp
->_errno
;
780 q
->_h_errno
= ai_resp
->_h_errno
;
782 l
= length
- sizeof(AddrInfoResponse
);
783 p
= (const uint8_t*) resp
+ sizeof(AddrInfoResponse
);
786 struct addrinfo
*ai
= NULL
;
788 r
= unserialize_addrinfo(&p
, &l
, &ai
);
793 freeaddrinfo(q
->addrinfo
);
806 return complete_query(resolve
, q
);
809 case RESPONSE_NAMEINFO
: {
810 const NameInfoResponse
*ni_resp
= &packet
->nameinfo_response
;
812 assert(length
>= sizeof(NameInfoResponse
));
813 assert(q
->type
== REQUEST_NAMEINFO
);
815 q
->ret
= ni_resp
->ret
;
816 q
->_errno
= ni_resp
->_errno
;
817 q
->_h_errno
= ni_resp
->_h_errno
;
819 if (ni_resp
->hostlen
> 0) {
820 q
->host
= strndup((const char*) ni_resp
+ sizeof(NameInfoResponse
), ni_resp
->hostlen
-1);
828 if (ni_resp
->servlen
> 0) {
829 q
->serv
= strndup((const char*) ni_resp
+ sizeof(NameInfoResponse
) + ni_resp
->hostlen
, ni_resp
->servlen
-1);
837 return complete_query(resolve
, q
);
845 _public_
int sd_resolve_process(sd_resolve
*resolve
) {
846 RESOLVE_DONT_DESTROY(resolve
);
850 uint8_t space
[BUFSIZE
];
855 assert_return(resolve
, -EINVAL
);
856 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
858 /* We don't allow recursively invoking sd_resolve_process(). */
859 assert_return(!resolve
->current
, -EBUSY
);
861 l
= recv(resolve
->fds
[RESPONSE_RECV_FD
], &buf
, sizeof(buf
), 0);
869 return -ECONNREFUSED
;
871 r
= handle_response(resolve
, &buf
.packet
, (size_t) l
);
878 _public_
int sd_resolve_wait(sd_resolve
*resolve
, uint64_t timeout_usec
) {
881 assert_return(resolve
, -EINVAL
);
882 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
884 if (resolve
->n_done
>= resolve
->n_queries
)
888 r
= fd_wait_for_event(resolve
->fds
[RESPONSE_RECV_FD
], POLLIN
, timeout_usec
);
889 } while (r
== -EINTR
);
894 return sd_resolve_process(resolve
);
897 static int alloc_query(sd_resolve
*resolve
, bool floating
, sd_resolve_query
**_q
) {
904 if (resolve
->n_queries
>= QUERIES_MAX
)
907 r
= start_threads(resolve
, 1);
911 while (resolve
->query_array
[resolve
->current_id
% QUERIES_MAX
])
912 resolve
->current_id
++;
914 q
= resolve
->query_array
[resolve
->current_id
% QUERIES_MAX
] = new0(sd_resolve_query
, 1);
919 q
->resolve
= resolve
;
920 q
->floating
= floating
;
921 q
->id
= resolve
->current_id
++;
924 sd_resolve_ref(resolve
);
926 LIST_PREPEND(queries
, resolve
->queries
, q
);
927 resolve
->n_queries
++;
933 _public_
int sd_resolve_getaddrinfo(
935 sd_resolve_query
**_q
,
936 const char *node
, const char *service
,
937 const struct addrinfo
*hints
,
938 sd_resolve_getaddrinfo_handler_t callback
, void *userdata
) {
940 AddrInfoRequest req
= {};
941 struct msghdr mh
= {};
946 assert_return(resolve
, -EINVAL
);
947 assert_return(node
|| service
, -EINVAL
);
948 assert_return(callback
, -EINVAL
);
949 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
951 r
= alloc_query(resolve
, !_q
, &q
);
955 q
->type
= REQUEST_ADDRINFO
;
956 q
->getaddrinfo_handler
= callback
;
957 q
->userdata
= userdata
;
959 req
.node_len
= node
? strlen(node
)+1 : 0;
960 req
.service_len
= service
? strlen(service
)+1 : 0;
962 req
.header
.id
= q
->id
;
963 req
.header
.type
= REQUEST_ADDRINFO
;
964 req
.header
.length
= sizeof(AddrInfoRequest
) + req
.node_len
+ req
.service_len
;
967 req
.hints_valid
= true;
968 req
.ai_flags
= hints
->ai_flags
;
969 req
.ai_family
= hints
->ai_family
;
970 req
.ai_socktype
= hints
->ai_socktype
;
971 req
.ai_protocol
= hints
->ai_protocol
;
974 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= &req
, .iov_len
= sizeof(AddrInfoRequest
) };
976 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= (void*) node
, .iov_len
= req
.node_len
};
978 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= (void*) service
, .iov_len
= req
.service_len
};
981 if (sendmsg(resolve
->fds
[REQUEST_SEND_FD
], &mh
, MSG_NOSIGNAL
) < 0) {
982 sd_resolve_query_unref(q
);
986 resolve
->n_outstanding
++;
994 static int getaddrinfo_done(sd_resolve_query
* q
) {
997 assert(q
->getaddrinfo_handler
);
1000 h_errno
= q
->_h_errno
;
1002 return q
->getaddrinfo_handler(q
, q
->ret
, q
->addrinfo
, q
->userdata
);
1005 _public_
int sd_resolve_getnameinfo(
1006 sd_resolve
*resolve
,
1007 sd_resolve_query
**_q
,
1008 const struct sockaddr
*sa
, socklen_t salen
,
1011 sd_resolve_getnameinfo_handler_t callback
,
1014 NameInfoRequest req
= {};
1015 struct msghdr mh
= {};
1016 struct iovec iov
[2];
1017 sd_resolve_query
*q
;
1020 assert_return(resolve
, -EINVAL
);
1021 assert_return(sa
, -EINVAL
);
1022 assert_return(salen
>= sizeof(struct sockaddr
), -EINVAL
);
1023 assert_return(salen
<= sizeof(union sockaddr_union
), -EINVAL
);
1024 assert_return((get
& ~SD_RESOLVE_GET_BOTH
) == 0, -EINVAL
);
1025 assert_return(callback
, -EINVAL
);
1026 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
1028 r
= alloc_query(resolve
, !_q
, &q
);
1032 q
->type
= REQUEST_NAMEINFO
;
1033 q
->getnameinfo_handler
= callback
;
1034 q
->userdata
= userdata
;
1036 req
.header
.id
= q
->id
;
1037 req
.header
.type
= REQUEST_NAMEINFO
;
1038 req
.header
.length
= sizeof(NameInfoRequest
) + salen
;
1041 req
.sockaddr_len
= salen
;
1042 req
.gethost
= !!(get
& SD_RESOLVE_GET_HOST
);
1043 req
.getserv
= !!(get
& SD_RESOLVE_GET_SERVICE
);
1045 iov
[0] = (struct iovec
) { .iov_base
= &req
, .iov_len
= sizeof(NameInfoRequest
) };
1046 iov
[1] = (struct iovec
) { .iov_base
= (void*) sa
, .iov_len
= salen
};
1051 if (sendmsg(resolve
->fds
[REQUEST_SEND_FD
], &mh
, MSG_NOSIGNAL
) < 0) {
1052 sd_resolve_query_unref(q
);
1056 resolve
->n_outstanding
++;
1064 static int getnameinfo_done(sd_resolve_query
*q
) {
1068 assert(q
->getnameinfo_handler
);
1071 h_errno
= q
->_h_errno
;
1073 return q
->getnameinfo_handler(q
, q
->ret
, q
->host
, q
->serv
, q
->userdata
);
1076 _public_ sd_resolve_query
* sd_resolve_query_ref(sd_resolve_query
*q
) {
1077 assert_return(q
, NULL
);
1079 assert(q
->n_ref
>= 1);
1085 static void resolve_freeaddrinfo(struct addrinfo
*ai
) {
1087 struct addrinfo
*next
= ai
->ai_next
;
1090 free(ai
->ai_canonname
);
1096 static void resolve_query_disconnect(sd_resolve_query
*q
) {
1097 sd_resolve
*resolve
;
1105 resolve
= q
->resolve
;
1106 assert(resolve
->n_queries
> 0);
1109 assert(resolve
->n_done
> 0);
1113 i
= q
->id
% QUERIES_MAX
;
1114 assert(resolve
->query_array
[i
] == q
);
1115 resolve
->query_array
[i
] = NULL
;
1116 LIST_REMOVE(queries
, resolve
->queries
, q
);
1117 resolve
->n_queries
--;
1121 sd_resolve_unref(resolve
);
1124 static void resolve_query_free(sd_resolve_query
*q
) {
1127 resolve_query_disconnect(q
);
1129 resolve_freeaddrinfo(q
->addrinfo
);
1135 _public_ sd_resolve_query
* sd_resolve_query_unref(sd_resolve_query
* q
) {
1139 assert(q
->n_ref
>= 1);
1143 resolve_query_free(q
);
1148 _public_
int sd_resolve_query_is_done(sd_resolve_query
*q
) {
1149 assert_return(q
, -EINVAL
);
1150 assert_return(!resolve_pid_changed(q
->resolve
), -ECHILD
);
1155 _public_
void* sd_resolve_query_set_userdata(sd_resolve_query
*q
, void *userdata
) {
1158 assert_return(q
, NULL
);
1159 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1162 q
->userdata
= userdata
;
1167 _public_
void* sd_resolve_query_get_userdata(sd_resolve_query
*q
) {
1168 assert_return(q
, NULL
);
1169 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1174 _public_ sd_resolve
*sd_resolve_query_get_resolve(sd_resolve_query
*q
) {
1175 assert_return(q
, NULL
);
1176 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1181 static int io_callback(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
1182 sd_resolve
*resolve
= userdata
;
1187 r
= sd_resolve_process(resolve
);
1194 _public_
int sd_resolve_attach_event(sd_resolve
*resolve
, sd_event
*event
, int64_t priority
) {
1197 assert_return(resolve
, -EINVAL
);
1198 assert_return(!resolve
->event
, -EBUSY
);
1200 assert(!resolve
->event_source
);
1203 resolve
->event
= sd_event_ref(event
);
1205 r
= sd_event_default(&resolve
->event
);
1210 r
= sd_event_add_io(resolve
->event
, &resolve
->event_source
, resolve
->fds
[RESPONSE_RECV_FD
], POLLIN
, io_callback
, resolve
);
1214 r
= sd_event_source_set_priority(resolve
->event_source
, priority
);
1221 sd_resolve_detach_event(resolve
);
1225 _public_
int sd_resolve_detach_event(sd_resolve
*resolve
) {
1226 assert_return(resolve
, -EINVAL
);
1228 if (!resolve
->event
)
1231 if (resolve
->event_source
) {
1232 sd_event_source_set_enabled(resolve
->event_source
, SD_EVENT_OFF
);
1233 resolve
->event_source
= sd_event_source_unref(resolve
->event_source
);
1236 resolve
->event
= sd_event_unref(resolve
->event
);
1240 _public_ sd_event
*sd_resolve_get_event(sd_resolve
*resolve
) {
1241 assert_return(resolve
, NULL
);
1243 return resolve
->event
;