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
);
896 return sd_resolve_process(resolve
);
899 static int alloc_query(sd_resolve
*resolve
, bool floating
, sd_resolve_query
**_q
) {
906 if (resolve
->n_queries
>= QUERIES_MAX
)
909 r
= start_threads(resolve
, 1);
913 while (resolve
->query_array
[resolve
->current_id
% QUERIES_MAX
])
914 resolve
->current_id
++;
916 q
= resolve
->query_array
[resolve
->current_id
% QUERIES_MAX
] = new0(sd_resolve_query
, 1);
921 q
->resolve
= resolve
;
922 q
->floating
= floating
;
923 q
->id
= resolve
->current_id
++;
926 sd_resolve_ref(resolve
);
928 LIST_PREPEND(queries
, resolve
->queries
, q
);
929 resolve
->n_queries
++;
935 _public_
int sd_resolve_getaddrinfo(
937 sd_resolve_query
**_q
,
938 const char *node
, const char *service
,
939 const struct addrinfo
*hints
,
940 sd_resolve_getaddrinfo_handler_t callback
, void *userdata
) {
942 AddrInfoRequest req
= {};
943 struct msghdr mh
= {};
948 assert_return(resolve
, -EINVAL
);
949 assert_return(node
|| service
, -EINVAL
);
950 assert_return(callback
, -EINVAL
);
951 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
953 r
= alloc_query(resolve
, !_q
, &q
);
957 q
->type
= REQUEST_ADDRINFO
;
958 q
->getaddrinfo_handler
= callback
;
959 q
->userdata
= userdata
;
961 req
.node_len
= node
? strlen(node
)+1 : 0;
962 req
.service_len
= service
? strlen(service
)+1 : 0;
964 req
.header
.id
= q
->id
;
965 req
.header
.type
= REQUEST_ADDRINFO
;
966 req
.header
.length
= sizeof(AddrInfoRequest
) + req
.node_len
+ req
.service_len
;
969 req
.hints_valid
= true;
970 req
.ai_flags
= hints
->ai_flags
;
971 req
.ai_family
= hints
->ai_family
;
972 req
.ai_socktype
= hints
->ai_socktype
;
973 req
.ai_protocol
= hints
->ai_protocol
;
976 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= &req
, .iov_len
= sizeof(AddrInfoRequest
) };
978 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= (void*) node
, .iov_len
= req
.node_len
};
980 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= (void*) service
, .iov_len
= req
.service_len
};
983 if (sendmsg(resolve
->fds
[REQUEST_SEND_FD
], &mh
, MSG_NOSIGNAL
) < 0) {
984 sd_resolve_query_unref(q
);
988 resolve
->n_outstanding
++;
996 static int getaddrinfo_done(sd_resolve_query
* q
) {
999 assert(q
->getaddrinfo_handler
);
1002 h_errno
= q
->_h_errno
;
1004 return q
->getaddrinfo_handler(q
, q
->ret
, q
->addrinfo
, q
->userdata
);
1007 _public_
int sd_resolve_getnameinfo(
1008 sd_resolve
*resolve
,
1009 sd_resolve_query
**_q
,
1010 const struct sockaddr
*sa
, socklen_t salen
,
1013 sd_resolve_getnameinfo_handler_t callback
,
1016 NameInfoRequest req
= {};
1017 struct msghdr mh
= {};
1018 struct iovec iov
[2];
1019 sd_resolve_query
*q
;
1022 assert_return(resolve
, -EINVAL
);
1023 assert_return(sa
, -EINVAL
);
1024 assert_return(salen
>= sizeof(struct sockaddr
), -EINVAL
);
1025 assert_return(salen
<= sizeof(union sockaddr_union
), -EINVAL
);
1026 assert_return((get
& ~SD_RESOLVE_GET_BOTH
) == 0, -EINVAL
);
1027 assert_return(callback
, -EINVAL
);
1028 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
1030 r
= alloc_query(resolve
, !_q
, &q
);
1034 q
->type
= REQUEST_NAMEINFO
;
1035 q
->getnameinfo_handler
= callback
;
1036 q
->userdata
= userdata
;
1038 req
.header
.id
= q
->id
;
1039 req
.header
.type
= REQUEST_NAMEINFO
;
1040 req
.header
.length
= sizeof(NameInfoRequest
) + salen
;
1043 req
.sockaddr_len
= salen
;
1044 req
.gethost
= !!(get
& SD_RESOLVE_GET_HOST
);
1045 req
.getserv
= !!(get
& SD_RESOLVE_GET_SERVICE
);
1047 iov
[0] = (struct iovec
) { .iov_base
= &req
, .iov_len
= sizeof(NameInfoRequest
) };
1048 iov
[1] = (struct iovec
) { .iov_base
= (void*) sa
, .iov_len
= salen
};
1053 if (sendmsg(resolve
->fds
[REQUEST_SEND_FD
], &mh
, MSG_NOSIGNAL
) < 0) {
1054 sd_resolve_query_unref(q
);
1058 resolve
->n_outstanding
++;
1066 static int getnameinfo_done(sd_resolve_query
*q
) {
1070 assert(q
->getnameinfo_handler
);
1073 h_errno
= q
->_h_errno
;
1075 return q
->getnameinfo_handler(q
, q
->ret
, q
->host
, q
->serv
, q
->userdata
);
1078 _public_ sd_resolve_query
* sd_resolve_query_ref(sd_resolve_query
*q
) {
1079 assert_return(q
, NULL
);
1081 assert(q
->n_ref
>= 1);
1087 static void resolve_freeaddrinfo(struct addrinfo
*ai
) {
1089 struct addrinfo
*next
= ai
->ai_next
;
1092 free(ai
->ai_canonname
);
1098 static void resolve_query_disconnect(sd_resolve_query
*q
) {
1099 sd_resolve
*resolve
;
1107 resolve
= q
->resolve
;
1108 assert(resolve
->n_queries
> 0);
1111 assert(resolve
->n_done
> 0);
1115 i
= q
->id
% QUERIES_MAX
;
1116 assert(resolve
->query_array
[i
] == q
);
1117 resolve
->query_array
[i
] = NULL
;
1118 LIST_REMOVE(queries
, resolve
->queries
, q
);
1119 resolve
->n_queries
--;
1123 sd_resolve_unref(resolve
);
1126 static void resolve_query_free(sd_resolve_query
*q
) {
1129 resolve_query_disconnect(q
);
1131 resolve_freeaddrinfo(q
->addrinfo
);
1137 _public_ sd_resolve_query
* sd_resolve_query_unref(sd_resolve_query
* q
) {
1141 assert(q
->n_ref
>= 1);
1145 resolve_query_free(q
);
1150 _public_
int sd_resolve_query_is_done(sd_resolve_query
*q
) {
1151 assert_return(q
, -EINVAL
);
1152 assert_return(!resolve_pid_changed(q
->resolve
), -ECHILD
);
1157 _public_
void* sd_resolve_query_set_userdata(sd_resolve_query
*q
, void *userdata
) {
1160 assert_return(q
, NULL
);
1161 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1164 q
->userdata
= userdata
;
1169 _public_
void* sd_resolve_query_get_userdata(sd_resolve_query
*q
) {
1170 assert_return(q
, NULL
);
1171 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1176 _public_ sd_resolve
*sd_resolve_query_get_resolve(sd_resolve_query
*q
) {
1177 assert_return(q
, NULL
);
1178 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1183 static int io_callback(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
1184 sd_resolve
*resolve
= userdata
;
1189 r
= sd_resolve_process(resolve
);
1196 _public_
int sd_resolve_attach_event(sd_resolve
*resolve
, sd_event
*event
, int64_t priority
) {
1199 assert_return(resolve
, -EINVAL
);
1200 assert_return(!resolve
->event
, -EBUSY
);
1202 assert(!resolve
->event_source
);
1205 resolve
->event
= sd_event_ref(event
);
1207 r
= sd_event_default(&resolve
->event
);
1212 r
= sd_event_add_io(resolve
->event
, &resolve
->event_source
, resolve
->fds
[RESPONSE_RECV_FD
], POLLIN
, io_callback
, resolve
);
1216 r
= sd_event_source_set_priority(resolve
->event_source
, priority
);
1223 sd_resolve_detach_event(resolve
);
1227 _public_
int sd_resolve_detach_event(sd_resolve
*resolve
) {
1228 assert_return(resolve
, -EINVAL
);
1230 if (!resolve
->event
)
1233 if (resolve
->event_source
) {
1234 sd_event_source_set_enabled(resolve
->event_source
, SD_EVENT_OFF
);
1235 resolve
->event_source
= sd_event_source_unref(resolve
->event_source
);
1238 resolve
->event
= sd_event_unref(resolve
->event
);
1242 _public_ sd_event
*sd_resolve_get_event(sd_resolve
*resolve
) {
1243 assert_return(resolve
, NULL
);
1245 return resolve
->event
;