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>
34 #include "sd-resolve.h"
40 #include "resolve-util.h"
41 #include "socket-util.h"
44 #define WORKERS_MIN 1U
45 #define WORKERS_MAX 16U
46 #define QUERIES_MAX 256U
47 #define BUFSIZE 10240U
74 pthread_t workers
[WORKERS_MAX
];
75 unsigned n_valid_workers
;
78 sd_resolve_query
* query_array
[QUERIES_MAX
];
79 unsigned n_queries
, n_done
, n_outstanding
;
81 sd_event_source
*event_source
;
84 sd_resolve_query
*current
;
86 sd_resolve
**default_resolve_ptr
;
89 LIST_HEAD(sd_resolve_query
, queries
);
92 struct sd_resolve_query
{
105 struct addrinfo
*addrinfo
;
109 sd_resolve_getaddrinfo_handler_t getaddrinfo_handler
;
110 sd_resolve_getnameinfo_handler_t getnameinfo_handler
;
115 LIST_FIELDS(sd_resolve_query
, queries
);
118 typedef struct RHeader
{
124 typedef struct AddrInfoRequest
{
125 struct RHeader header
;
131 size_t node_len
, service_len
;
134 typedef struct AddrInfoResponse
{
135 struct RHeader header
;
139 /* followed by addrinfo_serialization[] */
142 typedef struct AddrInfoSerialization
{
148 size_t canonname_len
;
149 /* Followed by ai_addr amd ai_canonname with variable lengths */
150 } AddrInfoSerialization
;
152 typedef struct NameInfoRequest
{
153 struct RHeader header
;
155 socklen_t sockaddr_len
;
156 bool gethost
:1, getserv
:1;
159 typedef struct NameInfoResponse
{
160 struct RHeader header
;
161 size_t hostlen
, servlen
;
167 typedef union Packet
{
169 AddrInfoRequest addrinfo_request
;
170 AddrInfoResponse addrinfo_response
;
171 NameInfoRequest nameinfo_request
;
172 NameInfoResponse nameinfo_response
;
175 static int getaddrinfo_done(sd_resolve_query
* q
);
176 static int getnameinfo_done(sd_resolve_query
*q
);
178 static void resolve_query_disconnect(sd_resolve_query
*q
);
180 #define RESOLVE_DONT_DESTROY(resolve) \
181 _cleanup_resolve_unref_ _unused_ sd_resolve *_dont_destroy_##resolve = sd_resolve_ref(resolve)
183 static int send_died(int out_fd
) {
186 .type
= RESPONSE_DIED
,
187 .length
= sizeof(RHeader
),
192 if (send(out_fd
, &rh
, rh
.length
, MSG_NOSIGNAL
) < 0)
198 static void *serialize_addrinfo(void *p
, const struct addrinfo
*ai
, size_t *length
, size_t maxlength
) {
199 AddrInfoSerialization s
;
205 assert(*length
<= maxlength
);
207 cnl
= ai
->ai_canonname
? strlen(ai
->ai_canonname
)+1 : 0;
208 l
= sizeof(AddrInfoSerialization
) + ai
->ai_addrlen
+ cnl
;
210 if (*length
+ l
> maxlength
)
213 s
.ai_flags
= ai
->ai_flags
;
214 s
.ai_family
= ai
->ai_family
;
215 s
.ai_socktype
= ai
->ai_socktype
;
216 s
.ai_protocol
= ai
->ai_protocol
;
217 s
.ai_addrlen
= ai
->ai_addrlen
;
218 s
.canonname_len
= cnl
;
220 memcpy((uint8_t*) p
, &s
, sizeof(AddrInfoSerialization
));
221 memcpy((uint8_t*) p
+ sizeof(AddrInfoSerialization
), ai
->ai_addr
, ai
->ai_addrlen
);
223 if (ai
->ai_canonname
)
224 memcpy((char*) p
+ sizeof(AddrInfoSerialization
) + ai
->ai_addrlen
, 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
;
404 /* No signals in this thread please */
405 assert_se(sigfillset(&fullset
) == 0);
406 assert_se(pthread_sigmask(SIG_BLOCK
, &fullset
, NULL
) == 0);
408 /* Assign a pretty name to this thread */
409 prctl(PR_SET_NAME
, (unsigned long) "sd-resolve");
411 while (!resolve
->dead
) {
414 uint8_t space
[BUFSIZE
];
418 length
= recv(resolve
->fds
[REQUEST_RECV_FD
], &buf
, sizeof(buf
), 0);
431 if (handle_request(resolve
->fds
[RESPONSE_SEND_FD
], &buf
.packet
, (size_t) length
) < 0)
435 send_died(resolve
->fds
[RESPONSE_SEND_FD
]);
440 static int start_threads(sd_resolve
*resolve
, unsigned extra
) {
444 n
= resolve
->n_outstanding
+ extra
;
445 n
= CLAMP(n
, WORKERS_MIN
, WORKERS_MAX
);
447 while (resolve
->n_valid_workers
< n
) {
449 r
= pthread_create(&resolve
->workers
[resolve
->n_valid_workers
], NULL
, thread_worker
, resolve
);
453 resolve
->n_valid_workers
++;
459 static bool resolve_pid_changed(sd_resolve
*r
) {
462 /* We don't support people creating a resolver and keeping it
463 * around after fork(). Let's complain. */
465 return r
->original_pid
!= getpid();
468 _public_
int sd_resolve_new(sd_resolve
**ret
) {
469 sd_resolve
*resolve
= NULL
;
472 assert_return(ret
, -EINVAL
);
474 resolve
= new0(sd_resolve
, 1);
479 resolve
->original_pid
= getpid();
481 for (i
= 0; i
< _FD_MAX
; i
++)
482 resolve
->fds
[i
] = -1;
484 r
= socketpair(PF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0, resolve
->fds
+ REQUEST_RECV_FD
);
490 r
= socketpair(PF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0, resolve
->fds
+ RESPONSE_RECV_FD
);
496 fd_inc_sndbuf(resolve
->fds
[REQUEST_SEND_FD
], QUERIES_MAX
* BUFSIZE
);
497 fd_inc_rcvbuf(resolve
->fds
[REQUEST_RECV_FD
], QUERIES_MAX
* BUFSIZE
);
498 fd_inc_sndbuf(resolve
->fds
[RESPONSE_SEND_FD
], QUERIES_MAX
* BUFSIZE
);
499 fd_inc_rcvbuf(resolve
->fds
[RESPONSE_RECV_FD
], QUERIES_MAX
* BUFSIZE
);
501 fd_nonblock(resolve
->fds
[RESPONSE_RECV_FD
], true);
507 sd_resolve_unref(resolve
);
511 _public_
int sd_resolve_default(sd_resolve
**ret
) {
513 static thread_local sd_resolve
*default_resolve
= NULL
;
514 sd_resolve
*e
= NULL
;
518 return !!default_resolve
;
520 if (default_resolve
) {
521 *ret
= sd_resolve_ref(default_resolve
);
525 r
= sd_resolve_new(&e
);
529 e
->default_resolve_ptr
= &default_resolve
;
537 _public_
int sd_resolve_get_tid(sd_resolve
*resolve
, pid_t
*tid
) {
538 assert_return(resolve
, -EINVAL
);
539 assert_return(tid
, -EINVAL
);
540 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
542 if (resolve
->tid
!= 0) {
548 return sd_event_get_tid(resolve
->event
, tid
);
553 static void resolve_free(sd_resolve
*resolve
) {
560 while ((q
= resolve
->queries
)) {
562 resolve_query_disconnect(q
);
563 sd_resolve_query_unref(q
);
566 if (resolve
->default_resolve_ptr
)
567 *(resolve
->default_resolve_ptr
) = NULL
;
569 resolve
->dead
= true;
571 sd_resolve_detach_event(resolve
);
573 if (resolve
->fds
[REQUEST_SEND_FD
] >= 0) {
576 .type
= REQUEST_TERMINATE
,
577 .length
= sizeof(req
)
580 /* Send one termination packet for each worker */
581 for (i
= 0; i
< resolve
->n_valid_workers
; i
++)
582 (void) send(resolve
->fds
[REQUEST_SEND_FD
], &req
, req
.length
, MSG_NOSIGNAL
);
585 /* Now terminate them and wait until they are gone. */
586 for (i
= 0; i
< resolve
->n_valid_workers
; i
++) {
588 if (pthread_join(resolve
->workers
[i
], NULL
) != EINTR
)
593 /* Close all communication channels */
594 for (i
= 0; i
< _FD_MAX
; i
++)
595 safe_close(resolve
->fds
[i
]);
600 _public_ sd_resolve
* sd_resolve_ref(sd_resolve
*resolve
) {
601 assert_return(resolve
, NULL
);
603 assert(resolve
->n_ref
>= 1);
609 _public_ sd_resolve
* sd_resolve_unref(sd_resolve
*resolve
) {
614 assert(resolve
->n_ref
>= 1);
617 if (resolve
->n_ref
<= 0)
618 resolve_free(resolve
);
623 _public_
int sd_resolve_get_fd(sd_resolve
*resolve
) {
624 assert_return(resolve
, -EINVAL
);
625 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
627 return resolve
->fds
[RESPONSE_RECV_FD
];
630 _public_
int sd_resolve_get_events(sd_resolve
*resolve
) {
631 assert_return(resolve
, -EINVAL
);
632 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
634 return resolve
->n_queries
> resolve
->n_done
? POLLIN
: 0;
637 _public_
int sd_resolve_get_timeout(sd_resolve
*resolve
, uint64_t *usec
) {
638 assert_return(resolve
, -EINVAL
);
639 assert_return(usec
, -EINVAL
);
640 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
642 *usec
= (uint64_t) -1;
646 static sd_resolve_query
*lookup_query(sd_resolve
*resolve
, unsigned id
) {
651 q
= resolve
->query_array
[id
% QUERIES_MAX
];
659 static int complete_query(sd_resolve
*resolve
, sd_resolve_query
*q
) {
664 assert(q
->resolve
== resolve
);
669 resolve
->current
= sd_resolve_query_ref(q
);
673 case REQUEST_ADDRINFO
:
674 r
= getaddrinfo_done(q
);
677 case REQUEST_NAMEINFO
:
678 r
= getnameinfo_done(q
);
682 assert_not_reached("Cannot complete unknown query type");
685 resolve
->current
= NULL
;
688 resolve_query_disconnect(q
);
689 sd_resolve_query_unref(q
);
692 sd_resolve_query_unref(q
);
697 static int unserialize_addrinfo(const void **p
, size_t *length
, struct addrinfo
**ret_ai
) {
698 AddrInfoSerialization s
;
707 if (*length
< sizeof(AddrInfoSerialization
))
710 memcpy(&s
, *p
, sizeof(s
));
712 l
= sizeof(AddrInfoSerialization
) + s
.ai_addrlen
+ s
.canonname_len
;
716 ai
= new0(struct addrinfo
, 1);
720 ai
->ai_flags
= s
.ai_flags
;
721 ai
->ai_family
= s
.ai_family
;
722 ai
->ai_socktype
= s
.ai_socktype
;
723 ai
->ai_protocol
= s
.ai_protocol
;
724 ai
->ai_addrlen
= s
.ai_addrlen
;
726 if (s
.ai_addrlen
> 0) {
727 ai
->ai_addr
= memdup((const uint8_t*) *p
+ sizeof(AddrInfoSerialization
), s
.ai_addrlen
);
734 if (s
.canonname_len
> 0) {
735 ai
->ai_canonname
= memdup((const uint8_t*) *p
+ sizeof(AddrInfoSerialization
) + s
.ai_addrlen
, s
.canonname_len
);
736 if (!ai
->ai_canonname
) {
745 *p
= ((const uint8_t*) *p
) + l
;
750 static int handle_response(sd_resolve
*resolve
, const Packet
*packet
, size_t length
) {
757 resp
= &packet
->rheader
;
759 assert(length
>= sizeof(RHeader
));
760 assert(length
== resp
->length
);
762 if (resp
->type
== RESPONSE_DIED
) {
763 resolve
->dead
= true;
767 assert(resolve
->n_outstanding
> 0);
768 resolve
->n_outstanding
--;
770 q
= lookup_query(resolve
, resp
->id
);
774 switch (resp
->type
) {
776 case RESPONSE_ADDRINFO
: {
777 const AddrInfoResponse
*ai_resp
= &packet
->addrinfo_response
;
780 struct addrinfo
*prev
= NULL
;
782 assert(length
>= sizeof(AddrInfoResponse
));
783 assert(q
->type
== REQUEST_ADDRINFO
);
785 q
->ret
= ai_resp
->ret
;
786 q
->_errno
= ai_resp
->_errno
;
787 q
->_h_errno
= ai_resp
->_h_errno
;
789 l
= length
- sizeof(AddrInfoResponse
);
790 p
= (const uint8_t*) resp
+ sizeof(AddrInfoResponse
);
793 struct addrinfo
*ai
= NULL
;
795 r
= unserialize_addrinfo(&p
, &l
, &ai
);
800 freeaddrinfo(q
->addrinfo
);
813 return complete_query(resolve
, q
);
816 case RESPONSE_NAMEINFO
: {
817 const NameInfoResponse
*ni_resp
= &packet
->nameinfo_response
;
819 assert(length
>= sizeof(NameInfoResponse
));
820 assert(q
->type
== REQUEST_NAMEINFO
);
822 q
->ret
= ni_resp
->ret
;
823 q
->_errno
= ni_resp
->_errno
;
824 q
->_h_errno
= ni_resp
->_h_errno
;
826 if (ni_resp
->hostlen
> 0) {
827 q
->host
= strndup((const char*) ni_resp
+ sizeof(NameInfoResponse
), ni_resp
->hostlen
-1);
835 if (ni_resp
->servlen
> 0) {
836 q
->serv
= strndup((const char*) ni_resp
+ sizeof(NameInfoResponse
) + ni_resp
->hostlen
, ni_resp
->servlen
-1);
844 return complete_query(resolve
, q
);
852 _public_
int sd_resolve_process(sd_resolve
*resolve
) {
853 RESOLVE_DONT_DESTROY(resolve
);
857 uint8_t space
[BUFSIZE
];
862 assert_return(resolve
, -EINVAL
);
863 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
865 /* We don't allow recursively invoking sd_resolve_process(). */
866 assert_return(!resolve
->current
, -EBUSY
);
868 l
= recv(resolve
->fds
[RESPONSE_RECV_FD
], &buf
, sizeof(buf
), 0);
876 return -ECONNREFUSED
;
878 r
= handle_response(resolve
, &buf
.packet
, (size_t) l
);
885 _public_
int sd_resolve_wait(sd_resolve
*resolve
, uint64_t timeout_usec
) {
888 assert_return(resolve
, -EINVAL
);
889 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
891 if (resolve
->n_done
>= resolve
->n_queries
)
895 r
= fd_wait_for_event(resolve
->fds
[RESPONSE_RECV_FD
], POLLIN
, timeout_usec
);
896 } while (r
== -EINTR
);
901 return sd_resolve_process(resolve
);
904 static int alloc_query(sd_resolve
*resolve
, bool floating
, sd_resolve_query
**_q
) {
911 if (resolve
->n_queries
>= QUERIES_MAX
)
914 r
= start_threads(resolve
, 1);
918 while (resolve
->query_array
[resolve
->current_id
% QUERIES_MAX
])
919 resolve
->current_id
++;
921 q
= resolve
->query_array
[resolve
->current_id
% QUERIES_MAX
] = new0(sd_resolve_query
, 1);
926 q
->resolve
= resolve
;
927 q
->floating
= floating
;
928 q
->id
= resolve
->current_id
++;
931 sd_resolve_ref(resolve
);
933 LIST_PREPEND(queries
, resolve
->queries
, q
);
934 resolve
->n_queries
++;
940 _public_
int sd_resolve_getaddrinfo(
942 sd_resolve_query
**_q
,
943 const char *node
, const char *service
,
944 const struct addrinfo
*hints
,
945 sd_resolve_getaddrinfo_handler_t callback
, void *userdata
) {
947 AddrInfoRequest req
= {};
948 struct msghdr mh
= {};
953 assert_return(resolve
, -EINVAL
);
954 assert_return(node
|| service
, -EINVAL
);
955 assert_return(callback
, -EINVAL
);
956 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
958 r
= alloc_query(resolve
, !_q
, &q
);
962 q
->type
= REQUEST_ADDRINFO
;
963 q
->getaddrinfo_handler
= callback
;
964 q
->userdata
= userdata
;
966 req
.node_len
= node
? strlen(node
)+1 : 0;
967 req
.service_len
= service
? strlen(service
)+1 : 0;
969 req
.header
.id
= q
->id
;
970 req
.header
.type
= REQUEST_ADDRINFO
;
971 req
.header
.length
= sizeof(AddrInfoRequest
) + req
.node_len
+ req
.service_len
;
974 req
.hints_valid
= true;
975 req
.ai_flags
= hints
->ai_flags
;
976 req
.ai_family
= hints
->ai_family
;
977 req
.ai_socktype
= hints
->ai_socktype
;
978 req
.ai_protocol
= hints
->ai_protocol
;
981 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= &req
, .iov_len
= sizeof(AddrInfoRequest
) };
983 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= (void*) node
, .iov_len
= req
.node_len
};
985 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= (void*) service
, .iov_len
= req
.service_len
};
988 if (sendmsg(resolve
->fds
[REQUEST_SEND_FD
], &mh
, MSG_NOSIGNAL
) < 0) {
989 sd_resolve_query_unref(q
);
993 resolve
->n_outstanding
++;
1001 static int getaddrinfo_done(sd_resolve_query
* q
) {
1004 assert(q
->getaddrinfo_handler
);
1007 h_errno
= q
->_h_errno
;
1009 return q
->getaddrinfo_handler(q
, q
->ret
, q
->addrinfo
, q
->userdata
);
1012 _public_
int sd_resolve_getnameinfo(
1013 sd_resolve
*resolve
,
1014 sd_resolve_query
**_q
,
1015 const struct sockaddr
*sa
, socklen_t salen
,
1018 sd_resolve_getnameinfo_handler_t callback
,
1021 NameInfoRequest req
= {};
1022 struct msghdr mh
= {};
1023 struct iovec iov
[2];
1024 sd_resolve_query
*q
;
1027 assert_return(resolve
, -EINVAL
);
1028 assert_return(sa
, -EINVAL
);
1029 assert_return(salen
>= sizeof(struct sockaddr
), -EINVAL
);
1030 assert_return(salen
<= sizeof(union sockaddr_union
), -EINVAL
);
1031 assert_return((get
& ~SD_RESOLVE_GET_BOTH
) == 0, -EINVAL
);
1032 assert_return(callback
, -EINVAL
);
1033 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
1035 r
= alloc_query(resolve
, !_q
, &q
);
1039 q
->type
= REQUEST_NAMEINFO
;
1040 q
->getnameinfo_handler
= callback
;
1041 q
->userdata
= userdata
;
1043 req
.header
.id
= q
->id
;
1044 req
.header
.type
= REQUEST_NAMEINFO
;
1045 req
.header
.length
= sizeof(NameInfoRequest
) + salen
;
1048 req
.sockaddr_len
= salen
;
1049 req
.gethost
= !!(get
& SD_RESOLVE_GET_HOST
);
1050 req
.getserv
= !!(get
& SD_RESOLVE_GET_SERVICE
);
1052 iov
[0] = (struct iovec
) { .iov_base
= &req
, .iov_len
= sizeof(NameInfoRequest
) };
1053 iov
[1] = (struct iovec
) { .iov_base
= (void*) sa
, .iov_len
= salen
};
1058 if (sendmsg(resolve
->fds
[REQUEST_SEND_FD
], &mh
, MSG_NOSIGNAL
) < 0) {
1059 sd_resolve_query_unref(q
);
1063 resolve
->n_outstanding
++;
1071 static int getnameinfo_done(sd_resolve_query
*q
) {
1075 assert(q
->getnameinfo_handler
);
1078 h_errno
= q
->_h_errno
;
1080 return q
->getnameinfo_handler(q
, q
->ret
, q
->host
, q
->serv
, q
->userdata
);
1083 _public_ sd_resolve_query
* sd_resolve_query_ref(sd_resolve_query
*q
) {
1084 assert_return(q
, NULL
);
1086 assert(q
->n_ref
>= 1);
1092 static void resolve_freeaddrinfo(struct addrinfo
*ai
) {
1094 struct addrinfo
*next
= ai
->ai_next
;
1097 free(ai
->ai_canonname
);
1103 static void resolve_query_disconnect(sd_resolve_query
*q
) {
1104 sd_resolve
*resolve
;
1112 resolve
= q
->resolve
;
1113 assert(resolve
->n_queries
> 0);
1116 assert(resolve
->n_done
> 0);
1120 i
= q
->id
% QUERIES_MAX
;
1121 assert(resolve
->query_array
[i
] == q
);
1122 resolve
->query_array
[i
] = NULL
;
1123 LIST_REMOVE(queries
, resolve
->queries
, q
);
1124 resolve
->n_queries
--;
1128 sd_resolve_unref(resolve
);
1131 static void resolve_query_free(sd_resolve_query
*q
) {
1134 resolve_query_disconnect(q
);
1136 resolve_freeaddrinfo(q
->addrinfo
);
1142 _public_ sd_resolve_query
* sd_resolve_query_unref(sd_resolve_query
* q
) {
1146 assert(q
->n_ref
>= 1);
1150 resolve_query_free(q
);
1155 _public_
int sd_resolve_query_is_done(sd_resolve_query
*q
) {
1156 assert_return(q
, -EINVAL
);
1157 assert_return(!resolve_pid_changed(q
->resolve
), -ECHILD
);
1162 _public_
void* sd_resolve_query_set_userdata(sd_resolve_query
*q
, void *userdata
) {
1165 assert_return(q
, NULL
);
1166 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1169 q
->userdata
= userdata
;
1174 _public_
void* sd_resolve_query_get_userdata(sd_resolve_query
*q
) {
1175 assert_return(q
, NULL
);
1176 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1181 _public_ sd_resolve
*sd_resolve_query_get_resolve(sd_resolve_query
*q
) {
1182 assert_return(q
, NULL
);
1183 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1188 static int io_callback(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
1189 sd_resolve
*resolve
= userdata
;
1194 r
= sd_resolve_process(resolve
);
1201 _public_
int sd_resolve_attach_event(sd_resolve
*resolve
, sd_event
*event
, int priority
) {
1204 assert_return(resolve
, -EINVAL
);
1205 assert_return(!resolve
->event
, -EBUSY
);
1207 assert(!resolve
->event_source
);
1210 resolve
->event
= sd_event_ref(event
);
1212 r
= sd_event_default(&resolve
->event
);
1217 r
= sd_event_add_io(resolve
->event
, &resolve
->event_source
, resolve
->fds
[RESPONSE_RECV_FD
], POLLIN
, io_callback
, resolve
);
1221 r
= sd_event_source_set_priority(resolve
->event_source
, priority
);
1228 sd_resolve_detach_event(resolve
);
1232 _public_
int sd_resolve_detach_event(sd_resolve
*resolve
) {
1233 assert_return(resolve
, -EINVAL
);
1235 if (!resolve
->event
)
1238 if (resolve
->event_source
) {
1239 sd_event_source_set_enabled(resolve
->event_source
, SD_EVENT_OFF
);
1240 resolve
->event_source
= sd_event_source_unref(resolve
->event_source
);
1243 resolve
->event
= sd_event_unref(resolve
->event
);
1247 _public_ sd_event
*sd_resolve_get_event(sd_resolve
*resolve
) {
1248 assert_return(resolve
, NULL
);
1250 return resolve
->event
;