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"
38 #include "resolve-util.h"
39 #include "socket-util.h"
42 #define WORKERS_MIN 1U
43 #define WORKERS_MAX 16U
44 #define QUERIES_MAX 256U
45 #define BUFSIZE 10240U
72 pthread_t workers
[WORKERS_MAX
];
73 unsigned n_valid_workers
;
76 sd_resolve_query
* query_array
[QUERIES_MAX
];
77 unsigned n_queries
, n_done
, n_outstanding
;
79 sd_event_source
*event_source
;
82 sd_resolve_query
*current
;
84 sd_resolve
**default_resolve_ptr
;
87 LIST_HEAD(sd_resolve_query
, queries
);
90 struct sd_resolve_query
{
103 struct addrinfo
*addrinfo
;
107 sd_resolve_getaddrinfo_handler_t getaddrinfo_handler
;
108 sd_resolve_getnameinfo_handler_t getnameinfo_handler
;
113 LIST_FIELDS(sd_resolve_query
, queries
);
116 typedef struct RHeader
{
122 typedef struct AddrInfoRequest
{
123 struct RHeader header
;
129 size_t node_len
, service_len
;
132 typedef struct AddrInfoResponse
{
133 struct RHeader header
;
137 /* followed by addrinfo_serialization[] */
140 typedef struct AddrInfoSerialization
{
146 size_t canonname_len
;
147 /* Followed by ai_addr amd ai_canonname with variable lengths */
148 } AddrInfoSerialization
;
150 typedef struct NameInfoRequest
{
151 struct RHeader header
;
153 socklen_t sockaddr_len
;
154 bool gethost
:1, getserv
:1;
157 typedef struct NameInfoResponse
{
158 struct RHeader header
;
159 size_t hostlen
, servlen
;
165 typedef union Packet
{
167 AddrInfoRequest addrinfo_request
;
168 AddrInfoResponse addrinfo_response
;
169 NameInfoRequest nameinfo_request
;
170 NameInfoResponse nameinfo_response
;
173 static int getaddrinfo_done(sd_resolve_query
* q
);
174 static int getnameinfo_done(sd_resolve_query
*q
);
176 static void resolve_query_disconnect(sd_resolve_query
*q
);
178 #define RESOLVE_DONT_DESTROY(resolve) \
179 _cleanup_resolve_unref_ _unused_ sd_resolve *_dont_destroy_##resolve = sd_resolve_ref(resolve)
181 static int send_died(int out_fd
) {
184 .type
= RESPONSE_DIED
,
185 .length
= sizeof(RHeader
),
190 if (send(out_fd
, &rh
, rh
.length
, MSG_NOSIGNAL
) < 0)
196 static void *serialize_addrinfo(void *p
, const struct addrinfo
*ai
, size_t *length
, size_t maxlength
) {
197 AddrInfoSerialization s
;
203 assert(*length
<= maxlength
);
205 cnl
= ai
->ai_canonname
? strlen(ai
->ai_canonname
)+1 : 0;
206 l
= sizeof(AddrInfoSerialization
) + ai
->ai_addrlen
+ cnl
;
208 if (*length
+ l
> maxlength
)
211 s
.ai_flags
= ai
->ai_flags
;
212 s
.ai_family
= ai
->ai_family
;
213 s
.ai_socktype
= ai
->ai_socktype
;
214 s
.ai_protocol
= ai
->ai_protocol
;
215 s
.ai_addrlen
= ai
->ai_addrlen
;
216 s
.canonname_len
= cnl
;
218 memcpy((uint8_t*) p
, &s
, sizeof(AddrInfoSerialization
));
219 memcpy((uint8_t*) p
+ sizeof(AddrInfoSerialization
), ai
->ai_addr
, ai
->ai_addrlen
);
221 if (ai
->ai_canonname
)
222 memcpy((char*) p
+ sizeof(AddrInfoSerialization
) + ai
->ai_addrlen
, 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 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();
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();
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 for (i
= 0; i
< resolve
->n_valid_workers
; i
++) {
586 if (pthread_join(resolve
->workers
[i
], NULL
) != EINTR
)
591 /* Close all communication channels */
592 for (i
= 0; i
< _FD_MAX
; i
++)
593 safe_close(resolve
->fds
[i
]);
598 _public_ sd_resolve
* sd_resolve_ref(sd_resolve
*resolve
) {
599 assert_return(resolve
, NULL
);
601 assert(resolve
->n_ref
>= 1);
607 _public_ sd_resolve
* sd_resolve_unref(sd_resolve
*resolve
) {
612 assert(resolve
->n_ref
>= 1);
615 if (resolve
->n_ref
<= 0)
616 resolve_free(resolve
);
621 _public_
int sd_resolve_get_fd(sd_resolve
*resolve
) {
622 assert_return(resolve
, -EINVAL
);
623 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
625 return resolve
->fds
[RESPONSE_RECV_FD
];
628 _public_
int sd_resolve_get_events(sd_resolve
*resolve
) {
629 assert_return(resolve
, -EINVAL
);
630 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
632 return resolve
->n_queries
> resolve
->n_done
? POLLIN
: 0;
635 _public_
int sd_resolve_get_timeout(sd_resolve
*resolve
, uint64_t *usec
) {
636 assert_return(resolve
, -EINVAL
);
637 assert_return(usec
, -EINVAL
);
638 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
640 *usec
= (uint64_t) -1;
644 static sd_resolve_query
*lookup_query(sd_resolve
*resolve
, unsigned id
) {
649 q
= resolve
->query_array
[id
% QUERIES_MAX
];
657 static int complete_query(sd_resolve
*resolve
, sd_resolve_query
*q
) {
662 assert(q
->resolve
== resolve
);
667 resolve
->current
= sd_resolve_query_ref(q
);
671 case REQUEST_ADDRINFO
:
672 r
= getaddrinfo_done(q
);
675 case REQUEST_NAMEINFO
:
676 r
= getnameinfo_done(q
);
680 assert_not_reached("Cannot complete unknown query type");
683 resolve
->current
= NULL
;
686 resolve_query_disconnect(q
);
687 sd_resolve_query_unref(q
);
690 sd_resolve_query_unref(q
);
695 static int unserialize_addrinfo(const void **p
, size_t *length
, struct addrinfo
**ret_ai
) {
696 AddrInfoSerialization s
;
705 if (*length
< sizeof(AddrInfoSerialization
))
708 memcpy(&s
, *p
, sizeof(s
));
710 l
= sizeof(AddrInfoSerialization
) + s
.ai_addrlen
+ s
.canonname_len
;
714 ai
= new0(struct addrinfo
, 1);
718 ai
->ai_flags
= s
.ai_flags
;
719 ai
->ai_family
= s
.ai_family
;
720 ai
->ai_socktype
= s
.ai_socktype
;
721 ai
->ai_protocol
= s
.ai_protocol
;
722 ai
->ai_addrlen
= s
.ai_addrlen
;
724 if (s
.ai_addrlen
> 0) {
725 ai
->ai_addr
= memdup((const uint8_t*) *p
+ sizeof(AddrInfoSerialization
), s
.ai_addrlen
);
732 if (s
.canonname_len
> 0) {
733 ai
->ai_canonname
= memdup((const uint8_t*) *p
+ sizeof(AddrInfoSerialization
) + s
.ai_addrlen
, s
.canonname_len
);
734 if (!ai
->ai_canonname
) {
743 *p
= ((const uint8_t*) *p
) + l
;
748 static int handle_response(sd_resolve
*resolve
, const Packet
*packet
, size_t length
) {
755 resp
= &packet
->rheader
;
757 assert(length
>= sizeof(RHeader
));
758 assert(length
== resp
->length
);
760 if (resp
->type
== RESPONSE_DIED
) {
761 resolve
->dead
= true;
765 assert(resolve
->n_outstanding
> 0);
766 resolve
->n_outstanding
--;
768 q
= lookup_query(resolve
, resp
->id
);
772 switch (resp
->type
) {
774 case RESPONSE_ADDRINFO
: {
775 const AddrInfoResponse
*ai_resp
= &packet
->addrinfo_response
;
778 struct addrinfo
*prev
= NULL
;
780 assert(length
>= sizeof(AddrInfoResponse
));
781 assert(q
->type
== REQUEST_ADDRINFO
);
783 q
->ret
= ai_resp
->ret
;
784 q
->_errno
= ai_resp
->_errno
;
785 q
->_h_errno
= ai_resp
->_h_errno
;
787 l
= length
- sizeof(AddrInfoResponse
);
788 p
= (const uint8_t*) resp
+ sizeof(AddrInfoResponse
);
791 struct addrinfo
*ai
= NULL
;
793 r
= unserialize_addrinfo(&p
, &l
, &ai
);
798 freeaddrinfo(q
->addrinfo
);
811 return complete_query(resolve
, q
);
814 case RESPONSE_NAMEINFO
: {
815 const NameInfoResponse
*ni_resp
= &packet
->nameinfo_response
;
817 assert(length
>= sizeof(NameInfoResponse
));
818 assert(q
->type
== REQUEST_NAMEINFO
);
820 q
->ret
= ni_resp
->ret
;
821 q
->_errno
= ni_resp
->_errno
;
822 q
->_h_errno
= ni_resp
->_h_errno
;
824 if (ni_resp
->hostlen
> 0) {
825 q
->host
= strndup((const char*) ni_resp
+ sizeof(NameInfoResponse
), ni_resp
->hostlen
-1);
833 if (ni_resp
->servlen
> 0) {
834 q
->serv
= strndup((const char*) ni_resp
+ sizeof(NameInfoResponse
) + ni_resp
->hostlen
, ni_resp
->servlen
-1);
842 return complete_query(resolve
, q
);
850 _public_
int sd_resolve_process(sd_resolve
*resolve
) {
851 RESOLVE_DONT_DESTROY(resolve
);
855 uint8_t space
[BUFSIZE
];
860 assert_return(resolve
, -EINVAL
);
861 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
863 /* We don't allow recursively invoking sd_resolve_process(). */
864 assert_return(!resolve
->current
, -EBUSY
);
866 l
= recv(resolve
->fds
[RESPONSE_RECV_FD
], &buf
, sizeof(buf
), 0);
874 return -ECONNREFUSED
;
876 r
= handle_response(resolve
, &buf
.packet
, (size_t) l
);
883 _public_
int sd_resolve_wait(sd_resolve
*resolve
, uint64_t timeout_usec
) {
886 assert_return(resolve
, -EINVAL
);
887 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
889 if (resolve
->n_done
>= resolve
->n_queries
)
893 r
= fd_wait_for_event(resolve
->fds
[RESPONSE_RECV_FD
], POLLIN
, timeout_usec
);
894 } while (r
== -EINTR
);
899 return sd_resolve_process(resolve
);
902 static int alloc_query(sd_resolve
*resolve
, bool floating
, sd_resolve_query
**_q
) {
909 if (resolve
->n_queries
>= QUERIES_MAX
)
912 r
= start_threads(resolve
, 1);
916 while (resolve
->query_array
[resolve
->current_id
% QUERIES_MAX
])
917 resolve
->current_id
++;
919 q
= resolve
->query_array
[resolve
->current_id
% QUERIES_MAX
] = new0(sd_resolve_query
, 1);
924 q
->resolve
= resolve
;
925 q
->floating
= floating
;
926 q
->id
= resolve
->current_id
++;
929 sd_resolve_ref(resolve
);
931 LIST_PREPEND(queries
, resolve
->queries
, q
);
932 resolve
->n_queries
++;
938 _public_
int sd_resolve_getaddrinfo(
940 sd_resolve_query
**_q
,
941 const char *node
, const char *service
,
942 const struct addrinfo
*hints
,
943 sd_resolve_getaddrinfo_handler_t callback
, void *userdata
) {
945 AddrInfoRequest req
= {};
946 struct msghdr mh
= {};
951 assert_return(resolve
, -EINVAL
);
952 assert_return(node
|| service
, -EINVAL
);
953 assert_return(callback
, -EINVAL
);
954 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
956 r
= alloc_query(resolve
, !_q
, &q
);
960 q
->type
= REQUEST_ADDRINFO
;
961 q
->getaddrinfo_handler
= callback
;
962 q
->userdata
= userdata
;
964 req
.node_len
= node
? strlen(node
)+1 : 0;
965 req
.service_len
= service
? strlen(service
)+1 : 0;
967 req
.header
.id
= q
->id
;
968 req
.header
.type
= REQUEST_ADDRINFO
;
969 req
.header
.length
= sizeof(AddrInfoRequest
) + req
.node_len
+ req
.service_len
;
972 req
.hints_valid
= true;
973 req
.ai_flags
= hints
->ai_flags
;
974 req
.ai_family
= hints
->ai_family
;
975 req
.ai_socktype
= hints
->ai_socktype
;
976 req
.ai_protocol
= hints
->ai_protocol
;
979 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= &req
, .iov_len
= sizeof(AddrInfoRequest
) };
981 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= (void*) node
, .iov_len
= req
.node_len
};
983 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= (void*) service
, .iov_len
= req
.service_len
};
986 if (sendmsg(resolve
->fds
[REQUEST_SEND_FD
], &mh
, MSG_NOSIGNAL
) < 0) {
987 sd_resolve_query_unref(q
);
991 resolve
->n_outstanding
++;
999 static int getaddrinfo_done(sd_resolve_query
* q
) {
1002 assert(q
->getaddrinfo_handler
);
1005 h_errno
= q
->_h_errno
;
1007 return q
->getaddrinfo_handler(q
, q
->ret
, q
->addrinfo
, q
->userdata
);
1010 _public_
int sd_resolve_getnameinfo(
1011 sd_resolve
*resolve
,
1012 sd_resolve_query
**_q
,
1013 const struct sockaddr
*sa
, socklen_t salen
,
1016 sd_resolve_getnameinfo_handler_t callback
,
1019 NameInfoRequest req
= {};
1020 struct msghdr mh
= {};
1021 struct iovec iov
[2];
1022 sd_resolve_query
*q
;
1025 assert_return(resolve
, -EINVAL
);
1026 assert_return(sa
, -EINVAL
);
1027 assert_return(salen
>= sizeof(struct sockaddr
), -EINVAL
);
1028 assert_return(salen
<= sizeof(union sockaddr_union
), -EINVAL
);
1029 assert_return((get
& ~SD_RESOLVE_GET_BOTH
) == 0, -EINVAL
);
1030 assert_return(callback
, -EINVAL
);
1031 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
1033 r
= alloc_query(resolve
, !_q
, &q
);
1037 q
->type
= REQUEST_NAMEINFO
;
1038 q
->getnameinfo_handler
= callback
;
1039 q
->userdata
= userdata
;
1041 req
.header
.id
= q
->id
;
1042 req
.header
.type
= REQUEST_NAMEINFO
;
1043 req
.header
.length
= sizeof(NameInfoRequest
) + salen
;
1046 req
.sockaddr_len
= salen
;
1047 req
.gethost
= !!(get
& SD_RESOLVE_GET_HOST
);
1048 req
.getserv
= !!(get
& SD_RESOLVE_GET_SERVICE
);
1050 iov
[0] = (struct iovec
) { .iov_base
= &req
, .iov_len
= sizeof(NameInfoRequest
) };
1051 iov
[1] = (struct iovec
) { .iov_base
= (void*) sa
, .iov_len
= salen
};
1056 if (sendmsg(resolve
->fds
[REQUEST_SEND_FD
], &mh
, MSG_NOSIGNAL
) < 0) {
1057 sd_resolve_query_unref(q
);
1061 resolve
->n_outstanding
++;
1069 static int getnameinfo_done(sd_resolve_query
*q
) {
1073 assert(q
->getnameinfo_handler
);
1076 h_errno
= q
->_h_errno
;
1078 return q
->getnameinfo_handler(q
, q
->ret
, q
->host
, q
->serv
, q
->userdata
);
1081 _public_ sd_resolve_query
* sd_resolve_query_ref(sd_resolve_query
*q
) {
1082 assert_return(q
, NULL
);
1084 assert(q
->n_ref
>= 1);
1090 static void resolve_freeaddrinfo(struct addrinfo
*ai
) {
1092 struct addrinfo
*next
= ai
->ai_next
;
1095 free(ai
->ai_canonname
);
1101 static void resolve_query_disconnect(sd_resolve_query
*q
) {
1102 sd_resolve
*resolve
;
1110 resolve
= q
->resolve
;
1111 assert(resolve
->n_queries
> 0);
1114 assert(resolve
->n_done
> 0);
1118 i
= q
->id
% QUERIES_MAX
;
1119 assert(resolve
->query_array
[i
] == q
);
1120 resolve
->query_array
[i
] = NULL
;
1121 LIST_REMOVE(queries
, resolve
->queries
, q
);
1122 resolve
->n_queries
--;
1126 sd_resolve_unref(resolve
);
1129 static void resolve_query_free(sd_resolve_query
*q
) {
1132 resolve_query_disconnect(q
);
1134 resolve_freeaddrinfo(q
->addrinfo
);
1140 _public_ sd_resolve_query
* sd_resolve_query_unref(sd_resolve_query
* q
) {
1144 assert(q
->n_ref
>= 1);
1148 resolve_query_free(q
);
1153 _public_
int sd_resolve_query_is_done(sd_resolve_query
*q
) {
1154 assert_return(q
, -EINVAL
);
1155 assert_return(!resolve_pid_changed(q
->resolve
), -ECHILD
);
1160 _public_
void* sd_resolve_query_set_userdata(sd_resolve_query
*q
, void *userdata
) {
1163 assert_return(q
, NULL
);
1164 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1167 q
->userdata
= userdata
;
1172 _public_
void* sd_resolve_query_get_userdata(sd_resolve_query
*q
) {
1173 assert_return(q
, NULL
);
1174 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1179 _public_ sd_resolve
*sd_resolve_query_get_resolve(sd_resolve_query
*q
) {
1180 assert_return(q
, NULL
);
1181 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1186 static int io_callback(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
1187 sd_resolve
*resolve
= userdata
;
1192 r
= sd_resolve_process(resolve
);
1199 _public_
int sd_resolve_attach_event(sd_resolve
*resolve
, sd_event
*event
, int priority
) {
1202 assert_return(resolve
, -EINVAL
);
1203 assert_return(!resolve
->event
, -EBUSY
);
1205 assert(!resolve
->event_source
);
1208 resolve
->event
= sd_event_ref(event
);
1210 r
= sd_event_default(&resolve
->event
);
1215 r
= sd_event_add_io(resolve
->event
, &resolve
->event_source
, resolve
->fds
[RESPONSE_RECV_FD
], POLLIN
, io_callback
, resolve
);
1219 r
= sd_event_source_set_priority(resolve
->event_source
, priority
);
1226 sd_resolve_detach_event(resolve
);
1230 _public_
int sd_resolve_detach_event(sd_resolve
*resolve
) {
1231 assert_return(resolve
, -EINVAL
);
1233 if (!resolve
->event
)
1236 if (resolve
->event_source
) {
1237 sd_event_source_set_enabled(resolve
->event_source
, SD_EVENT_OFF
);
1238 resolve
->event_source
= sd_event_source_unref(resolve
->event_source
);
1241 resolve
->event
= sd_event_unref(resolve
->event
);
1245 _public_ sd_event
*sd_resolve_get_event(sd_resolve
*resolve
) {
1246 assert_return(resolve
, NULL
);
1248 return resolve
->event
;