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"
36 #include "alloc-util.h"
41 #include "resolve-util.h"
42 #include "socket-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_resolve_unref_ _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
);
224 if (ai
->ai_canonname
)
225 memcpy((char*) p
+ sizeof(AddrInfoSerialization
) + ai
->ai_addrlen
, ai
->ai_canonname
, cnl
);
228 return (uint8_t*) p
+ l
;
231 static int send_addrinfo_reply(
239 AddrInfoResponse resp
= {
240 .header
.type
= RESPONSE_ADDRINFO
,
242 .header
.length
= sizeof(AddrInfoResponse
),
245 ._h_errno
= _h_errno
,
248 struct msghdr mh
= {};
251 AddrInfoSerialization ais
;
252 uint8_t space
[BUFSIZE
];
257 if (ret
== 0 && ai
) {
261 for (k
= ai
; k
; k
= k
->ai_next
) {
262 p
= serialize_addrinfo(p
, k
, &resp
.header
.length
, (uint8_t*) &buffer
+ BUFSIZE
- (uint8_t*) p
);
273 iov
[0] = (struct iovec
) { .iov_base
= &resp
, .iov_len
= sizeof(AddrInfoResponse
) };
274 iov
[1] = (struct iovec
) { .iov_base
= &buffer
, .iov_len
= resp
.header
.length
- sizeof(AddrInfoResponse
) };
277 mh
.msg_iovlen
= ELEMENTSOF(iov
);
279 if (sendmsg(out_fd
, &mh
, MSG_NOSIGNAL
) < 0)
285 static int send_nameinfo_reply(
294 NameInfoResponse resp
= {
295 .header
.type
= RESPONSE_NAMEINFO
,
299 ._h_errno
= _h_errno
,
302 struct msghdr mh
= {};
308 sl
= serv
? strlen(serv
)+1 : 0;
309 hl
= host
? strlen(host
)+1 : 0;
311 resp
.header
.length
= sizeof(NameInfoResponse
) + hl
+ sl
;
315 iov
[0] = (struct iovec
) { .iov_base
= &resp
, .iov_len
= sizeof(NameInfoResponse
) };
316 iov
[1] = (struct iovec
) { .iov_base
= (void*) host
, .iov_len
= hl
};
317 iov
[2] = (struct iovec
) { .iov_base
= (void*) serv
, .iov_len
= sl
};
320 mh
.msg_iovlen
= ELEMENTSOF(iov
);
322 if (sendmsg(out_fd
, &mh
, MSG_NOSIGNAL
) < 0)
328 static int handle_request(int out_fd
, const Packet
*packet
, size_t length
) {
334 req
= &packet
->rheader
;
336 assert(length
>= sizeof(RHeader
));
337 assert(length
== req
->length
);
341 case REQUEST_ADDRINFO
: {
342 const AddrInfoRequest
*ai_req
= &packet
->addrinfo_request
;
343 struct addrinfo hints
= {}, *result
= NULL
;
344 const char *node
, *service
;
347 assert(length
>= sizeof(AddrInfoRequest
));
348 assert(length
== sizeof(AddrInfoRequest
) + ai_req
->node_len
+ ai_req
->service_len
);
350 hints
.ai_flags
= ai_req
->ai_flags
;
351 hints
.ai_family
= ai_req
->ai_family
;
352 hints
.ai_socktype
= ai_req
->ai_socktype
;
353 hints
.ai_protocol
= ai_req
->ai_protocol
;
355 node
= ai_req
->node_len
? (const char*) ai_req
+ sizeof(AddrInfoRequest
) : NULL
;
356 service
= ai_req
->service_len
? (const char*) ai_req
+ sizeof(AddrInfoRequest
) + ai_req
->node_len
: NULL
;
360 ai_req
->hints_valid
? &hints
: NULL
,
363 /* send_addrinfo_reply() frees result */
364 return send_addrinfo_reply(out_fd
, req
->id
, ret
, result
, errno
, h_errno
);
367 case REQUEST_NAMEINFO
: {
368 const NameInfoRequest
*ni_req
= &packet
->nameinfo_request
;
369 char hostbuf
[NI_MAXHOST
], servbuf
[NI_MAXSERV
];
370 union sockaddr_union sa
;
373 assert(length
>= sizeof(NameInfoRequest
));
374 assert(length
== sizeof(NameInfoRequest
) + ni_req
->sockaddr_len
);
375 assert(sizeof(sa
) >= ni_req
->sockaddr_len
);
377 memcpy(&sa
, (const uint8_t *) ni_req
+ sizeof(NameInfoRequest
), ni_req
->sockaddr_len
);
379 ret
= getnameinfo(&sa
.sa
, ni_req
->sockaddr_len
,
380 ni_req
->gethost
? hostbuf
: NULL
, ni_req
->gethost
? sizeof(hostbuf
) : 0,
381 ni_req
->getserv
? servbuf
: NULL
, ni_req
->getserv
? sizeof(servbuf
) : 0,
384 return send_nameinfo_reply(out_fd
, req
->id
, ret
,
385 ret
== 0 && ni_req
->gethost
? hostbuf
: NULL
,
386 ret
== 0 && ni_req
->getserv
? servbuf
: NULL
,
390 case REQUEST_TERMINATE
:
395 assert_not_reached("Unknown request");
401 static void* thread_worker(void *p
) {
402 sd_resolve
*resolve
= p
;
405 /* No signals in this thread please */
406 assert_se(sigfillset(&fullset
) == 0);
407 assert_se(pthread_sigmask(SIG_BLOCK
, &fullset
, NULL
) == 0);
409 /* Assign a pretty name to this thread */
410 prctl(PR_SET_NAME
, (unsigned long) "sd-resolve");
412 while (!resolve
->dead
) {
415 uint8_t space
[BUFSIZE
];
419 length
= recv(resolve
->fds
[REQUEST_RECV_FD
], &buf
, sizeof(buf
), 0);
432 if (handle_request(resolve
->fds
[RESPONSE_SEND_FD
], &buf
.packet
, (size_t) length
) < 0)
436 send_died(resolve
->fds
[RESPONSE_SEND_FD
]);
441 static int start_threads(sd_resolve
*resolve
, unsigned extra
) {
445 n
= resolve
->n_outstanding
+ extra
;
446 n
= CLAMP(n
, WORKERS_MIN
, WORKERS_MAX
);
448 while (resolve
->n_valid_workers
< n
) {
450 r
= pthread_create(&resolve
->workers
[resolve
->n_valid_workers
], NULL
, thread_worker
, resolve
);
454 resolve
->n_valid_workers
++;
460 static bool resolve_pid_changed(sd_resolve
*r
) {
463 /* We don't support people creating a resolver and keeping it
464 * around after fork(). Let's complain. */
466 return r
->original_pid
!= getpid();
469 _public_
int sd_resolve_new(sd_resolve
**ret
) {
470 sd_resolve
*resolve
= NULL
;
473 assert_return(ret
, -EINVAL
);
475 resolve
= new0(sd_resolve
, 1);
480 resolve
->original_pid
= getpid();
482 for (i
= 0; i
< _FD_MAX
; i
++)
483 resolve
->fds
[i
] = -1;
485 r
= socketpair(PF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0, resolve
->fds
+ REQUEST_RECV_FD
);
491 r
= socketpair(PF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0, resolve
->fds
+ RESPONSE_RECV_FD
);
497 fd_inc_sndbuf(resolve
->fds
[REQUEST_SEND_FD
], QUERIES_MAX
* BUFSIZE
);
498 fd_inc_rcvbuf(resolve
->fds
[REQUEST_RECV_FD
], QUERIES_MAX
* BUFSIZE
);
499 fd_inc_sndbuf(resolve
->fds
[RESPONSE_SEND_FD
], QUERIES_MAX
* BUFSIZE
);
500 fd_inc_rcvbuf(resolve
->fds
[RESPONSE_RECV_FD
], QUERIES_MAX
* BUFSIZE
);
502 fd_nonblock(resolve
->fds
[RESPONSE_RECV_FD
], true);
508 sd_resolve_unref(resolve
);
512 _public_
int sd_resolve_default(sd_resolve
**ret
) {
514 static thread_local sd_resolve
*default_resolve
= NULL
;
515 sd_resolve
*e
= NULL
;
519 return !!default_resolve
;
521 if (default_resolve
) {
522 *ret
= sd_resolve_ref(default_resolve
);
526 r
= sd_resolve_new(&e
);
530 e
->default_resolve_ptr
= &default_resolve
;
538 _public_
int sd_resolve_get_tid(sd_resolve
*resolve
, pid_t
*tid
) {
539 assert_return(resolve
, -EINVAL
);
540 assert_return(tid
, -EINVAL
);
541 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
543 if (resolve
->tid
!= 0) {
549 return sd_event_get_tid(resolve
->event
, tid
);
554 static void resolve_free(sd_resolve
*resolve
) {
561 while ((q
= resolve
->queries
)) {
563 resolve_query_disconnect(q
);
564 sd_resolve_query_unref(q
);
567 if (resolve
->default_resolve_ptr
)
568 *(resolve
->default_resolve_ptr
) = NULL
;
570 resolve
->dead
= true;
572 sd_resolve_detach_event(resolve
);
574 if (resolve
->fds
[REQUEST_SEND_FD
] >= 0) {
577 .type
= REQUEST_TERMINATE
,
578 .length
= sizeof(req
)
581 /* Send one termination packet for each worker */
582 for (i
= 0; i
< resolve
->n_valid_workers
; i
++)
583 (void) send(resolve
->fds
[REQUEST_SEND_FD
], &req
, req
.length
, MSG_NOSIGNAL
);
586 /* Now terminate them and wait until they are gone. */
587 for (i
= 0; i
< resolve
->n_valid_workers
; i
++)
588 pthread_join(resolve
->workers
[i
], NULL
);
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
;