1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2005-2008 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
31 #include <sys/prctl.h>
36 #include "socket-util.h"
38 #include "resolve-util.h"
39 #include "sd-resolve.h"
41 #define WORKERS_MIN 1U
42 #define WORKERS_MAX 16U
43 #define QUERIES_MAX 256U
44 #define BUFSIZE 10240U
71 pthread_t workers
[WORKERS_MAX
];
72 unsigned n_valid_workers
;
75 sd_resolve_query
* query_array
[QUERIES_MAX
];
76 unsigned n_queries
, n_done
, n_outstanding
;
78 sd_event_source
*event_source
;
81 sd_resolve_query
*current
;
83 sd_resolve
**default_resolve_ptr
;
86 LIST_HEAD(sd_resolve_query
, queries
);
89 struct sd_resolve_query
{
102 struct addrinfo
*addrinfo
;
106 sd_resolve_getaddrinfo_handler_t getaddrinfo_handler
;
107 sd_resolve_getnameinfo_handler_t getnameinfo_handler
;
112 LIST_FIELDS(sd_resolve_query
, queries
);
115 typedef struct RHeader
{
121 typedef struct AddrInfoRequest
{
122 struct RHeader header
;
128 size_t node_len
, service_len
;
131 typedef struct AddrInfoResponse
{
132 struct RHeader header
;
136 /* followed by addrinfo_serialization[] */
139 typedef struct AddrInfoSerialization
{
145 size_t canonname_len
;
146 /* Followed by ai_addr amd ai_canonname with variable lengths */
147 } AddrInfoSerialization
;
149 typedef struct NameInfoRequest
{
150 struct RHeader header
;
152 socklen_t sockaddr_len
;
153 bool gethost
:1, getserv
:1;
156 typedef struct NameInfoResponse
{
157 struct RHeader header
;
158 size_t hostlen
, servlen
;
164 typedef union Packet
{
166 AddrInfoRequest addrinfo_request
;
167 AddrInfoResponse addrinfo_response
;
168 NameInfoRequest nameinfo_request
;
169 NameInfoResponse nameinfo_response
;
172 static int getaddrinfo_done(sd_resolve_query
* q
);
173 static int getnameinfo_done(sd_resolve_query
*q
);
175 static void resolve_query_disconnect(sd_resolve_query
*q
);
177 #define RESOLVE_DONT_DESTROY(resolve) \
178 _cleanup_resolve_unref_ _unused_ sd_resolve *_dont_destroy_##resolve = sd_resolve_ref(resolve)
180 static int send_died(int out_fd
) {
183 .type
= RESPONSE_DIED
,
184 .length
= sizeof(RHeader
),
189 if (send(out_fd
, &rh
, rh
.length
, MSG_NOSIGNAL
) < 0)
195 static void *serialize_addrinfo(void *p
, const struct addrinfo
*ai
, size_t *length
, size_t maxlength
) {
196 AddrInfoSerialization s
;
202 assert(*length
<= maxlength
);
204 cnl
= ai
->ai_canonname
? strlen(ai
->ai_canonname
)+1 : 0;
205 l
= sizeof(AddrInfoSerialization
) + ai
->ai_addrlen
+ cnl
;
207 if (*length
+ l
> maxlength
)
210 s
.ai_flags
= ai
->ai_flags
;
211 s
.ai_family
= ai
->ai_family
;
212 s
.ai_socktype
= ai
->ai_socktype
;
213 s
.ai_protocol
= ai
->ai_protocol
;
214 s
.ai_addrlen
= ai
->ai_addrlen
;
215 s
.canonname_len
= cnl
;
217 memcpy((uint8_t*) p
, &s
, sizeof(AddrInfoSerialization
));
218 memcpy((uint8_t*) p
+ sizeof(AddrInfoSerialization
), ai
->ai_addr
, ai
->ai_addrlen
);
220 if (ai
->ai_canonname
)
221 memcpy((char*) p
+ sizeof(AddrInfoSerialization
) + ai
->ai_addrlen
, ai
->ai_canonname
, cnl
);
224 return (uint8_t*) p
+ l
;
227 static int send_addrinfo_reply(
235 AddrInfoResponse resp
= {
236 .header
.type
= RESPONSE_ADDRINFO
,
238 .header
.length
= sizeof(AddrInfoResponse
),
241 ._h_errno
= _h_errno
,
244 struct msghdr mh
= {};
247 AddrInfoSerialization ais
;
248 uint8_t space
[BUFSIZE
];
253 if (ret
== 0 && ai
) {
257 for (k
= ai
; k
; k
= k
->ai_next
) {
258 p
= serialize_addrinfo(p
, k
, &resp
.header
.length
, (uint8_t*) &buffer
+ BUFSIZE
- (uint8_t*) p
);
269 iov
[0] = (struct iovec
) { .iov_base
= &resp
, .iov_len
= sizeof(AddrInfoResponse
) };
270 iov
[1] = (struct iovec
) { .iov_base
= &buffer
, .iov_len
= resp
.header
.length
- sizeof(AddrInfoResponse
) };
273 mh
.msg_iovlen
= ELEMENTSOF(iov
);
275 if (sendmsg(out_fd
, &mh
, MSG_NOSIGNAL
) < 0)
281 static int send_nameinfo_reply(
290 NameInfoResponse resp
= {
291 .header
.type
= RESPONSE_NAMEINFO
,
295 ._h_errno
= _h_errno
,
298 struct msghdr mh
= {};
304 sl
= serv
? strlen(serv
)+1 : 0;
305 hl
= host
? strlen(host
)+1 : 0;
307 resp
.header
.length
= sizeof(NameInfoResponse
) + hl
+ sl
;
311 iov
[0] = (struct iovec
) { .iov_base
= &resp
, .iov_len
= sizeof(NameInfoResponse
) };
312 iov
[1] = (struct iovec
) { .iov_base
= (void*) host
, .iov_len
= hl
};
313 iov
[2] = (struct iovec
) { .iov_base
= (void*) serv
, .iov_len
= sl
};
316 mh
.msg_iovlen
= ELEMENTSOF(iov
);
318 if (sendmsg(out_fd
, &mh
, MSG_NOSIGNAL
) < 0)
324 static int handle_request(int out_fd
, const Packet
*packet
, size_t length
) {
330 req
= &packet
->rheader
;
332 assert(length
>= sizeof(RHeader
));
333 assert(length
== req
->length
);
337 case REQUEST_ADDRINFO
: {
338 const AddrInfoRequest
*ai_req
= &packet
->addrinfo_request
;
339 struct addrinfo hints
= {}, *result
= NULL
;
340 const char *node
, *service
;
343 assert(length
>= sizeof(AddrInfoRequest
));
344 assert(length
== sizeof(AddrInfoRequest
) + ai_req
->node_len
+ ai_req
->service_len
);
346 hints
.ai_flags
= ai_req
->ai_flags
;
347 hints
.ai_family
= ai_req
->ai_family
;
348 hints
.ai_socktype
= ai_req
->ai_socktype
;
349 hints
.ai_protocol
= ai_req
->ai_protocol
;
351 node
= ai_req
->node_len
? (const char*) ai_req
+ sizeof(AddrInfoRequest
) : NULL
;
352 service
= ai_req
->service_len
? (const char*) ai_req
+ sizeof(AddrInfoRequest
) + ai_req
->node_len
: NULL
;
356 ai_req
->hints_valid
? &hints
: NULL
,
359 /* send_addrinfo_reply() frees result */
360 return send_addrinfo_reply(out_fd
, req
->id
, ret
, result
, errno
, h_errno
);
363 case REQUEST_NAMEINFO
: {
364 const NameInfoRequest
*ni_req
= &packet
->nameinfo_request
;
365 char hostbuf
[NI_MAXHOST
], servbuf
[NI_MAXSERV
];
366 union sockaddr_union sa
;
369 assert(length
>= sizeof(NameInfoRequest
));
370 assert(length
== sizeof(NameInfoRequest
) + ni_req
->sockaddr_len
);
371 assert(sizeof(sa
) >= ni_req
->sockaddr_len
);
373 memcpy(&sa
, (const uint8_t *) ni_req
+ sizeof(NameInfoRequest
), ni_req
->sockaddr_len
);
375 ret
= getnameinfo(&sa
.sa
, ni_req
->sockaddr_len
,
376 ni_req
->gethost
? hostbuf
: NULL
, ni_req
->gethost
? sizeof(hostbuf
) : 0,
377 ni_req
->getserv
? servbuf
: NULL
, ni_req
->getserv
? sizeof(servbuf
) : 0,
380 return send_nameinfo_reply(out_fd
, req
->id
, ret
,
381 ret
== 0 && ni_req
->gethost
? hostbuf
: NULL
,
382 ret
== 0 && ni_req
->getserv
? servbuf
: NULL
,
386 case REQUEST_TERMINATE
:
391 assert_not_reached("Unknown request");
397 static void* thread_worker(void *p
) {
398 sd_resolve
*resolve
= p
;
401 /* No signals in this thread please */
402 assert_se(sigfillset(&fullset
) == 0);
403 assert_se(pthread_sigmask(SIG_BLOCK
, &fullset
, NULL
) == 0);
405 /* Assign a pretty name to this thread */
406 prctl(PR_SET_NAME
, (unsigned long) "sd-resolve");
408 while (!resolve
->dead
) {
411 uint8_t space
[BUFSIZE
];
415 length
= recv(resolve
->fds
[REQUEST_RECV_FD
], &buf
, sizeof(buf
), 0);
428 if (handle_request(resolve
->fds
[RESPONSE_SEND_FD
], &buf
.packet
, (size_t) length
) < 0)
432 send_died(resolve
->fds
[RESPONSE_SEND_FD
]);
437 static int start_threads(sd_resolve
*resolve
, unsigned extra
) {
441 n
= resolve
->n_outstanding
+ extra
;
442 n
= CLAMP(n
, WORKERS_MIN
, WORKERS_MAX
);
444 while (resolve
->n_valid_workers
< n
) {
446 r
= pthread_create(&resolve
->workers
[resolve
->n_valid_workers
], NULL
, thread_worker
, resolve
);
450 resolve
->n_valid_workers
++;
456 static bool resolve_pid_changed(sd_resolve
*r
) {
459 /* We don't support people creating a resolver and keeping it
460 * around after fork(). Let's complain. */
462 return r
->original_pid
!= getpid();
465 _public_
int sd_resolve_new(sd_resolve
**ret
) {
466 sd_resolve
*resolve
= NULL
;
469 assert_return(ret
, -EINVAL
);
471 resolve
= new0(sd_resolve
, 1);
476 resolve
->original_pid
= getpid();
478 for (i
= 0; i
< _FD_MAX
; i
++)
479 resolve
->fds
[i
] = -1;
481 r
= socketpair(PF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0, resolve
->fds
+ REQUEST_RECV_FD
);
487 r
= socketpair(PF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0, resolve
->fds
+ RESPONSE_RECV_FD
);
493 fd_inc_sndbuf(resolve
->fds
[REQUEST_SEND_FD
], QUERIES_MAX
* BUFSIZE
);
494 fd_inc_rcvbuf(resolve
->fds
[REQUEST_RECV_FD
], QUERIES_MAX
* BUFSIZE
);
495 fd_inc_sndbuf(resolve
->fds
[RESPONSE_SEND_FD
], QUERIES_MAX
* BUFSIZE
);
496 fd_inc_rcvbuf(resolve
->fds
[RESPONSE_RECV_FD
], QUERIES_MAX
* BUFSIZE
);
498 fd_nonblock(resolve
->fds
[RESPONSE_RECV_FD
], true);
504 sd_resolve_unref(resolve
);
508 _public_
int sd_resolve_default(sd_resolve
**ret
) {
510 static thread_local sd_resolve
*default_resolve
= NULL
;
511 sd_resolve
*e
= NULL
;
515 return !!default_resolve
;
517 if (default_resolve
) {
518 *ret
= sd_resolve_ref(default_resolve
);
522 r
= sd_resolve_new(&e
);
526 e
->default_resolve_ptr
= &default_resolve
;
534 _public_
int sd_resolve_get_tid(sd_resolve
*resolve
, pid_t
*tid
) {
535 assert_return(resolve
, -EINVAL
);
536 assert_return(tid
, -EINVAL
);
537 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
539 if (resolve
->tid
!= 0) {
545 return sd_event_get_tid(resolve
->event
, tid
);
550 static void resolve_free(sd_resolve
*resolve
) {
557 while ((q
= resolve
->queries
)) {
559 resolve_query_disconnect(q
);
560 sd_resolve_query_unref(q
);
563 if (resolve
->default_resolve_ptr
)
564 *(resolve
->default_resolve_ptr
) = NULL
;
566 resolve
->dead
= true;
568 sd_resolve_detach_event(resolve
);
570 if (resolve
->fds
[REQUEST_SEND_FD
] >= 0) {
573 .type
= REQUEST_TERMINATE
,
574 .length
= sizeof(req
)
577 /* Send one termination packet for each worker */
578 for (i
= 0; i
< resolve
->n_valid_workers
; i
++)
579 (void) send(resolve
->fds
[REQUEST_SEND_FD
], &req
, req
.length
, MSG_NOSIGNAL
);
582 /* Now terminate them and wait until they are gone. */
583 for (i
= 0; i
< resolve
->n_valid_workers
; i
++) {
585 if (pthread_join(resolve
->workers
[i
], NULL
) != EINTR
)
590 /* Close all communication channels */
591 for (i
= 0; i
< _FD_MAX
; i
++)
592 safe_close(resolve
->fds
[i
]);
597 _public_ sd_resolve
* sd_resolve_ref(sd_resolve
*resolve
) {
598 assert_return(resolve
, NULL
);
600 assert(resolve
->n_ref
>= 1);
606 _public_ sd_resolve
* sd_resolve_unref(sd_resolve
*resolve
) {
611 assert(resolve
->n_ref
>= 1);
614 if (resolve
->n_ref
<= 0)
615 resolve_free(resolve
);
620 _public_
int sd_resolve_get_fd(sd_resolve
*resolve
) {
621 assert_return(resolve
, -EINVAL
);
622 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
624 return resolve
->fds
[RESPONSE_RECV_FD
];
627 _public_
int sd_resolve_get_events(sd_resolve
*resolve
) {
628 assert_return(resolve
, -EINVAL
);
629 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
631 return resolve
->n_queries
> resolve
->n_done
? POLLIN
: 0;
634 _public_
int sd_resolve_get_timeout(sd_resolve
*resolve
, uint64_t *usec
) {
635 assert_return(resolve
, -EINVAL
);
636 assert_return(usec
, -EINVAL
);
637 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
639 *usec
= (uint64_t) -1;
643 static sd_resolve_query
*lookup_query(sd_resolve
*resolve
, unsigned id
) {
648 q
= resolve
->query_array
[id
% QUERIES_MAX
];
656 static int complete_query(sd_resolve
*resolve
, sd_resolve_query
*q
) {
661 assert(q
->resolve
== resolve
);
666 resolve
->current
= sd_resolve_query_ref(q
);
670 case REQUEST_ADDRINFO
:
671 r
= getaddrinfo_done(q
);
674 case REQUEST_NAMEINFO
:
675 r
= getnameinfo_done(q
);
679 assert_not_reached("Cannot complete unknown query type");
682 resolve
->current
= NULL
;
685 resolve_query_disconnect(q
);
686 sd_resolve_query_unref(q
);
689 sd_resolve_query_unref(q
);
694 static int unserialize_addrinfo(const void **p
, size_t *length
, struct addrinfo
**ret_ai
) {
695 AddrInfoSerialization s
;
704 if (*length
< sizeof(AddrInfoSerialization
))
707 memcpy(&s
, *p
, sizeof(s
));
709 l
= sizeof(AddrInfoSerialization
) + s
.ai_addrlen
+ s
.canonname_len
;
713 ai
= new0(struct addrinfo
, 1);
717 ai
->ai_flags
= s
.ai_flags
;
718 ai
->ai_family
= s
.ai_family
;
719 ai
->ai_socktype
= s
.ai_socktype
;
720 ai
->ai_protocol
= s
.ai_protocol
;
721 ai
->ai_addrlen
= s
.ai_addrlen
;
723 if (s
.ai_addrlen
> 0) {
724 ai
->ai_addr
= memdup((const uint8_t*) *p
+ sizeof(AddrInfoSerialization
), s
.ai_addrlen
);
731 if (s
.canonname_len
> 0) {
732 ai
->ai_canonname
= memdup((const uint8_t*) *p
+ sizeof(AddrInfoSerialization
) + s
.ai_addrlen
, s
.canonname_len
);
733 if (!ai
->ai_canonname
) {
742 *p
= ((const uint8_t*) *p
) + l
;
747 static int handle_response(sd_resolve
*resolve
, const Packet
*packet
, size_t length
) {
754 resp
= &packet
->rheader
;
756 assert(length
>= sizeof(RHeader
));
757 assert(length
== resp
->length
);
759 if (resp
->type
== RESPONSE_DIED
) {
760 resolve
->dead
= true;
764 assert(resolve
->n_outstanding
> 0);
765 resolve
->n_outstanding
--;
767 q
= lookup_query(resolve
, resp
->id
);
771 switch (resp
->type
) {
773 case RESPONSE_ADDRINFO
: {
774 const AddrInfoResponse
*ai_resp
= &packet
->addrinfo_response
;
777 struct addrinfo
*prev
= NULL
;
779 assert(length
>= sizeof(AddrInfoResponse
));
780 assert(q
->type
== REQUEST_ADDRINFO
);
782 q
->ret
= ai_resp
->ret
;
783 q
->_errno
= ai_resp
->_errno
;
784 q
->_h_errno
= ai_resp
->_h_errno
;
786 l
= length
- sizeof(AddrInfoResponse
);
787 p
= (const uint8_t*) resp
+ sizeof(AddrInfoResponse
);
790 struct addrinfo
*ai
= NULL
;
792 r
= unserialize_addrinfo(&p
, &l
, &ai
);
797 freeaddrinfo(q
->addrinfo
);
810 return complete_query(resolve
, q
);
813 case RESPONSE_NAMEINFO
: {
814 const NameInfoResponse
*ni_resp
= &packet
->nameinfo_response
;
816 assert(length
>= sizeof(NameInfoResponse
));
817 assert(q
->type
== REQUEST_NAMEINFO
);
819 q
->ret
= ni_resp
->ret
;
820 q
->_errno
= ni_resp
->_errno
;
821 q
->_h_errno
= ni_resp
->_h_errno
;
823 if (ni_resp
->hostlen
> 0) {
824 q
->host
= strndup((const char*) ni_resp
+ sizeof(NameInfoResponse
), ni_resp
->hostlen
-1);
832 if (ni_resp
->servlen
> 0) {
833 q
->serv
= strndup((const char*) ni_resp
+ sizeof(NameInfoResponse
) + ni_resp
->hostlen
, ni_resp
->servlen
-1);
841 return complete_query(resolve
, q
);
849 _public_
int sd_resolve_process(sd_resolve
*resolve
) {
850 RESOLVE_DONT_DESTROY(resolve
);
854 uint8_t space
[BUFSIZE
];
859 assert_return(resolve
, -EINVAL
);
860 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
862 /* We don't allow recursively invoking sd_resolve_process(). */
863 assert_return(!resolve
->current
, -EBUSY
);
865 l
= recv(resolve
->fds
[RESPONSE_RECV_FD
], &buf
, sizeof(buf
), 0);
873 return -ECONNREFUSED
;
875 r
= handle_response(resolve
, &buf
.packet
, (size_t) l
);
882 _public_
int sd_resolve_wait(sd_resolve
*resolve
, uint64_t timeout_usec
) {
885 assert_return(resolve
, -EINVAL
);
886 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
888 if (resolve
->n_done
>= resolve
->n_queries
)
892 r
= fd_wait_for_event(resolve
->fds
[RESPONSE_RECV_FD
], POLLIN
, timeout_usec
);
893 } while (r
== -EINTR
);
898 return sd_resolve_process(resolve
);
901 static int alloc_query(sd_resolve
*resolve
, bool floating
, sd_resolve_query
**_q
) {
908 if (resolve
->n_queries
>= QUERIES_MAX
)
911 r
= start_threads(resolve
, 1);
915 while (resolve
->query_array
[resolve
->current_id
% QUERIES_MAX
])
916 resolve
->current_id
++;
918 q
= resolve
->query_array
[resolve
->current_id
% QUERIES_MAX
] = new0(sd_resolve_query
, 1);
923 q
->resolve
= resolve
;
924 q
->floating
= floating
;
925 q
->id
= resolve
->current_id
++;
928 sd_resolve_ref(resolve
);
930 LIST_PREPEND(queries
, resolve
->queries
, q
);
931 resolve
->n_queries
++;
937 _public_
int sd_resolve_getaddrinfo(
939 sd_resolve_query
**_q
,
940 const char *node
, const char *service
,
941 const struct addrinfo
*hints
,
942 sd_resolve_getaddrinfo_handler_t callback
, void *userdata
) {
944 AddrInfoRequest req
= {};
945 struct msghdr mh
= {};
950 assert_return(resolve
, -EINVAL
);
951 assert_return(node
|| service
, -EINVAL
);
952 assert_return(callback
, -EINVAL
);
953 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
955 r
= alloc_query(resolve
, !_q
, &q
);
959 q
->type
= REQUEST_ADDRINFO
;
960 q
->getaddrinfo_handler
= callback
;
961 q
->userdata
= userdata
;
963 req
.node_len
= node
? strlen(node
)+1 : 0;
964 req
.service_len
= service
? strlen(service
)+1 : 0;
966 req
.header
.id
= q
->id
;
967 req
.header
.type
= REQUEST_ADDRINFO
;
968 req
.header
.length
= sizeof(AddrInfoRequest
) + req
.node_len
+ req
.service_len
;
971 req
.hints_valid
= true;
972 req
.ai_flags
= hints
->ai_flags
;
973 req
.ai_family
= hints
->ai_family
;
974 req
.ai_socktype
= hints
->ai_socktype
;
975 req
.ai_protocol
= hints
->ai_protocol
;
978 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= &req
, .iov_len
= sizeof(AddrInfoRequest
) };
980 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= (void*) node
, .iov_len
= req
.node_len
};
982 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= (void*) service
, .iov_len
= req
.service_len
};
985 if (sendmsg(resolve
->fds
[REQUEST_SEND_FD
], &mh
, MSG_NOSIGNAL
) < 0) {
986 sd_resolve_query_unref(q
);
990 resolve
->n_outstanding
++;
998 static int getaddrinfo_done(sd_resolve_query
* q
) {
1001 assert(q
->getaddrinfo_handler
);
1004 h_errno
= q
->_h_errno
;
1006 return q
->getaddrinfo_handler(q
, q
->ret
, q
->addrinfo
, q
->userdata
);
1009 _public_
int sd_resolve_getnameinfo(
1010 sd_resolve
*resolve
,
1011 sd_resolve_query
**_q
,
1012 const struct sockaddr
*sa
, socklen_t salen
,
1015 sd_resolve_getnameinfo_handler_t callback
,
1018 NameInfoRequest req
= {};
1019 struct msghdr mh
= {};
1020 struct iovec iov
[2];
1021 sd_resolve_query
*q
;
1024 assert_return(resolve
, -EINVAL
);
1025 assert_return(sa
, -EINVAL
);
1026 assert_return(salen
>= sizeof(struct sockaddr
), -EINVAL
);
1027 assert_return(salen
<= sizeof(union sockaddr_union
), -EINVAL
);
1028 assert_return((get
& ~SD_RESOLVE_GET_BOTH
) == 0, -EINVAL
);
1029 assert_return(callback
, -EINVAL
);
1030 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
1032 r
= alloc_query(resolve
, !_q
, &q
);
1036 q
->type
= REQUEST_NAMEINFO
;
1037 q
->getnameinfo_handler
= callback
;
1038 q
->userdata
= userdata
;
1040 req
.header
.id
= q
->id
;
1041 req
.header
.type
= REQUEST_NAMEINFO
;
1042 req
.header
.length
= sizeof(NameInfoRequest
) + salen
;
1045 req
.sockaddr_len
= salen
;
1046 req
.gethost
= !!(get
& SD_RESOLVE_GET_HOST
);
1047 req
.getserv
= !!(get
& SD_RESOLVE_GET_SERVICE
);
1049 iov
[0] = (struct iovec
) { .iov_base
= &req
, .iov_len
= sizeof(NameInfoRequest
) };
1050 iov
[1] = (struct iovec
) { .iov_base
= (void*) sa
, .iov_len
= salen
};
1055 if (sendmsg(resolve
->fds
[REQUEST_SEND_FD
], &mh
, MSG_NOSIGNAL
) < 0) {
1056 sd_resolve_query_unref(q
);
1060 resolve
->n_outstanding
++;
1068 static int getnameinfo_done(sd_resolve_query
*q
) {
1072 assert(q
->getnameinfo_handler
);
1075 h_errno
= q
->_h_errno
;
1077 return q
->getnameinfo_handler(q
, q
->ret
, q
->host
, q
->serv
, q
->userdata
);
1080 _public_ sd_resolve_query
* sd_resolve_query_ref(sd_resolve_query
*q
) {
1081 assert_return(q
, NULL
);
1083 assert(q
->n_ref
>= 1);
1089 static void resolve_freeaddrinfo(struct addrinfo
*ai
) {
1091 struct addrinfo
*next
= ai
->ai_next
;
1094 free(ai
->ai_canonname
);
1100 static void resolve_query_disconnect(sd_resolve_query
*q
) {
1101 sd_resolve
*resolve
;
1109 resolve
= q
->resolve
;
1110 assert(resolve
->n_queries
> 0);
1113 assert(resolve
->n_done
> 0);
1117 i
= q
->id
% QUERIES_MAX
;
1118 assert(resolve
->query_array
[i
] == q
);
1119 resolve
->query_array
[i
] = NULL
;
1120 LIST_REMOVE(queries
, resolve
->queries
, q
);
1121 resolve
->n_queries
--;
1125 sd_resolve_unref(resolve
);
1128 static void resolve_query_free(sd_resolve_query
*q
) {
1131 resolve_query_disconnect(q
);
1133 resolve_freeaddrinfo(q
->addrinfo
);
1139 _public_ sd_resolve_query
* sd_resolve_query_unref(sd_resolve_query
* q
) {
1143 assert(q
->n_ref
>= 1);
1147 resolve_query_free(q
);
1152 _public_
int sd_resolve_query_is_done(sd_resolve_query
*q
) {
1153 assert_return(q
, -EINVAL
);
1154 assert_return(!resolve_pid_changed(q
->resolve
), -ECHILD
);
1159 _public_
void* sd_resolve_query_set_userdata(sd_resolve_query
*q
, void *userdata
) {
1162 assert_return(q
, NULL
);
1163 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1166 q
->userdata
= userdata
;
1171 _public_
void* sd_resolve_query_get_userdata(sd_resolve_query
*q
) {
1172 assert_return(q
, NULL
);
1173 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1178 _public_ sd_resolve
*sd_resolve_query_get_resolve(sd_resolve_query
*q
) {
1179 assert_return(q
, NULL
);
1180 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1185 static int io_callback(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
1186 sd_resolve
*resolve
= userdata
;
1191 r
= sd_resolve_process(resolve
);
1198 _public_
int sd_resolve_attach_event(sd_resolve
*resolve
, sd_event
*event
, int priority
) {
1201 assert_return(resolve
, -EINVAL
);
1202 assert_return(!resolve
->event
, -EBUSY
);
1204 assert(!resolve
->event_source
);
1207 resolve
->event
= sd_event_ref(event
);
1209 r
= sd_event_default(&resolve
->event
);
1214 r
= sd_event_add_io(resolve
->event
, &resolve
->event_source
, resolve
->fds
[RESPONSE_RECV_FD
], POLLIN
, io_callback
, resolve
);
1218 r
= sd_event_source_set_priority(resolve
->event_source
, priority
);
1225 sd_resolve_detach_event(resolve
);
1229 _public_
int sd_resolve_detach_event(sd_resolve
*resolve
) {
1230 assert_return(resolve
, -EINVAL
);
1232 if (!resolve
->event
)
1235 if (resolve
->event_source
) {
1236 sd_event_source_set_enabled(resolve
->event_source
, SD_EVENT_OFF
);
1237 resolve
->event_source
= sd_event_source_unref(resolve
->event_source
);
1240 resolve
->event
= sd_event_unref(resolve
->event
);
1244 _public_ sd_event
*sd_resolve_get_event(sd_resolve
*resolve
) {
1245 assert_return(resolve
, NULL
);
1247 return resolve
->event
;