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"
39 #include "resolve-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_resolve_unref_ _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
);
222 if (ai
->ai_canonname
)
223 memcpy((char*) p
+ sizeof(AddrInfoSerialization
) + ai
->ai_addrlen
, ai
->ai_canonname
, cnl
);
226 return (uint8_t*) p
+ l
;
229 static int send_addrinfo_reply(
237 AddrInfoResponse resp
= {
238 .header
.type
= RESPONSE_ADDRINFO
,
240 .header
.length
= sizeof(AddrInfoResponse
),
243 ._h_errno
= _h_errno
,
246 struct msghdr mh
= {};
249 AddrInfoSerialization ais
;
250 uint8_t space
[BUFSIZE
];
255 if (ret
== 0 && ai
) {
259 for (k
= ai
; k
; k
= k
->ai_next
) {
260 p
= serialize_addrinfo(p
, k
, &resp
.header
.length
, (uint8_t*) &buffer
+ BUFSIZE
- (uint8_t*) p
);
271 iov
[0] = (struct iovec
) { .iov_base
= &resp
, .iov_len
= sizeof(AddrInfoResponse
) };
272 iov
[1] = (struct iovec
) { .iov_base
= &buffer
, .iov_len
= resp
.header
.length
- sizeof(AddrInfoResponse
) };
275 mh
.msg_iovlen
= ELEMENTSOF(iov
);
277 if (sendmsg(out_fd
, &mh
, MSG_NOSIGNAL
) < 0)
283 static int send_nameinfo_reply(
292 NameInfoResponse resp
= {
293 .header
.type
= RESPONSE_NAMEINFO
,
297 ._h_errno
= _h_errno
,
300 struct msghdr mh
= {};
306 sl
= serv
? strlen(serv
)+1 : 0;
307 hl
= host
? strlen(host
)+1 : 0;
309 resp
.header
.length
= sizeof(NameInfoResponse
) + hl
+ sl
;
313 iov
[0] = (struct iovec
) { .iov_base
= &resp
, .iov_len
= sizeof(NameInfoResponse
) };
314 iov
[1] = (struct iovec
) { .iov_base
= (void*) host
, .iov_len
= hl
};
315 iov
[2] = (struct iovec
) { .iov_base
= (void*) serv
, .iov_len
= sl
};
318 mh
.msg_iovlen
= ELEMENTSOF(iov
);
320 if (sendmsg(out_fd
, &mh
, MSG_NOSIGNAL
) < 0)
326 static int handle_request(int out_fd
, const Packet
*packet
, size_t length
) {
332 req
= &packet
->rheader
;
334 assert(length
>= sizeof(RHeader
));
335 assert(length
== req
->length
);
339 case REQUEST_ADDRINFO
: {
340 const AddrInfoRequest
*ai_req
= &packet
->addrinfo_request
;
341 struct addrinfo hints
= {}, *result
= NULL
;
342 const char *node
, *service
;
345 assert(length
>= sizeof(AddrInfoRequest
));
346 assert(length
== sizeof(AddrInfoRequest
) + ai_req
->node_len
+ ai_req
->service_len
);
348 hints
.ai_flags
= ai_req
->ai_flags
;
349 hints
.ai_family
= ai_req
->ai_family
;
350 hints
.ai_socktype
= ai_req
->ai_socktype
;
351 hints
.ai_protocol
= ai_req
->ai_protocol
;
353 node
= ai_req
->node_len
? (const char*) ai_req
+ sizeof(AddrInfoRequest
) : NULL
;
354 service
= ai_req
->service_len
? (const char*) ai_req
+ sizeof(AddrInfoRequest
) + ai_req
->node_len
: NULL
;
358 ai_req
->hints_valid
? &hints
: NULL
,
361 /* send_addrinfo_reply() frees result */
362 return send_addrinfo_reply(out_fd
, req
->id
, ret
, result
, errno
, h_errno
);
365 case REQUEST_NAMEINFO
: {
366 const NameInfoRequest
*ni_req
= &packet
->nameinfo_request
;
367 char hostbuf
[NI_MAXHOST
], servbuf
[NI_MAXSERV
];
368 union sockaddr_union sa
;
371 assert(length
>= sizeof(NameInfoRequest
));
372 assert(length
== sizeof(NameInfoRequest
) + ni_req
->sockaddr_len
);
373 assert(sizeof(sa
) >= ni_req
->sockaddr_len
);
375 memcpy(&sa
, (const uint8_t *) ni_req
+ sizeof(NameInfoRequest
), ni_req
->sockaddr_len
);
377 ret
= getnameinfo(&sa
.sa
, ni_req
->sockaddr_len
,
378 ni_req
->gethost
? hostbuf
: NULL
, ni_req
->gethost
? sizeof(hostbuf
) : 0,
379 ni_req
->getserv
? servbuf
: NULL
, ni_req
->getserv
? sizeof(servbuf
) : 0,
382 return send_nameinfo_reply(out_fd
, req
->id
, ret
,
383 ret
== 0 && ni_req
->gethost
? hostbuf
: NULL
,
384 ret
== 0 && ni_req
->getserv
? servbuf
: NULL
,
388 case REQUEST_TERMINATE
:
393 assert_not_reached("Unknown request");
399 static void* thread_worker(void *p
) {
400 sd_resolve
*resolve
= p
;
403 /* No signals in this thread please */
404 assert_se(sigfillset(&fullset
) == 0);
405 assert_se(pthread_sigmask(SIG_BLOCK
, &fullset
, NULL
) == 0);
407 /* Assign a pretty name to this thread */
408 prctl(PR_SET_NAME
, (unsigned long) "sd-resolve");
410 while (!resolve
->dead
) {
413 uint8_t space
[BUFSIZE
];
417 length
= recv(resolve
->fds
[REQUEST_RECV_FD
], &buf
, sizeof(buf
), 0);
430 if (handle_request(resolve
->fds
[RESPONSE_SEND_FD
], &buf
.packet
, (size_t) length
) < 0)
434 send_died(resolve
->fds
[RESPONSE_SEND_FD
]);
439 static int start_threads(sd_resolve
*resolve
, unsigned extra
) {
443 n
= resolve
->n_outstanding
+ extra
;
444 n
= CLAMP(n
, WORKERS_MIN
, WORKERS_MAX
);
446 while (resolve
->n_valid_workers
< n
) {
448 r
= pthread_create(&resolve
->workers
[resolve
->n_valid_workers
], NULL
, thread_worker
, resolve
);
452 resolve
->n_valid_workers
++;
458 static bool resolve_pid_changed(sd_resolve
*r
) {
461 /* We don't support people creating a resolver and keeping it
462 * around after fork(). Let's complain. */
464 return r
->original_pid
!= getpid();
467 _public_
int sd_resolve_new(sd_resolve
**ret
) {
468 sd_resolve
*resolve
= NULL
;
471 assert_return(ret
, -EINVAL
);
473 resolve
= new0(sd_resolve
, 1);
478 resolve
->original_pid
= getpid();
480 for (i
= 0; i
< _FD_MAX
; i
++)
481 resolve
->fds
[i
] = -1;
483 r
= socketpair(PF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0, resolve
->fds
+ REQUEST_RECV_FD
);
489 r
= socketpair(PF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0, resolve
->fds
+ RESPONSE_RECV_FD
);
495 fd_inc_sndbuf(resolve
->fds
[REQUEST_SEND_FD
], QUERIES_MAX
* BUFSIZE
);
496 fd_inc_rcvbuf(resolve
->fds
[REQUEST_RECV_FD
], QUERIES_MAX
* BUFSIZE
);
497 fd_inc_sndbuf(resolve
->fds
[RESPONSE_SEND_FD
], QUERIES_MAX
* BUFSIZE
);
498 fd_inc_rcvbuf(resolve
->fds
[RESPONSE_RECV_FD
], QUERIES_MAX
* BUFSIZE
);
500 fd_nonblock(resolve
->fds
[RESPONSE_RECV_FD
], true);
506 sd_resolve_unref(resolve
);
510 _public_
int sd_resolve_default(sd_resolve
**ret
) {
512 static thread_local sd_resolve
*default_resolve
= NULL
;
513 sd_resolve
*e
= NULL
;
517 return !!default_resolve
;
519 if (default_resolve
) {
520 *ret
= sd_resolve_ref(default_resolve
);
524 r
= sd_resolve_new(&e
);
528 e
->default_resolve_ptr
= &default_resolve
;
536 _public_
int sd_resolve_get_tid(sd_resolve
*resolve
, pid_t
*tid
) {
537 assert_return(resolve
, -EINVAL
);
538 assert_return(tid
, -EINVAL
);
539 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
541 if (resolve
->tid
!= 0) {
547 return sd_event_get_tid(resolve
->event
, tid
);
552 static void resolve_free(sd_resolve
*resolve
) {
559 while ((q
= resolve
->queries
)) {
561 resolve_query_disconnect(q
);
562 sd_resolve_query_unref(q
);
565 if (resolve
->default_resolve_ptr
)
566 *(resolve
->default_resolve_ptr
) = NULL
;
568 resolve
->dead
= true;
570 sd_resolve_detach_event(resolve
);
572 if (resolve
->fds
[REQUEST_SEND_FD
] >= 0) {
575 .type
= REQUEST_TERMINATE
,
576 .length
= sizeof(req
)
579 /* Send one termination packet for each worker */
580 for (i
= 0; i
< resolve
->n_valid_workers
; i
++)
581 (void) send(resolve
->fds
[REQUEST_SEND_FD
], &req
, req
.length
, MSG_NOSIGNAL
);
584 /* Now terminate them and wait until they are gone. */
585 for (i
= 0; i
< resolve
->n_valid_workers
; i
++) {
587 if (pthread_join(resolve
->workers
[i
], NULL
) != EINTR
)
592 /* Close all communication channels */
593 for (i
= 0; i
< _FD_MAX
; i
++)
594 safe_close(resolve
->fds
[i
]);
599 _public_ sd_resolve
* sd_resolve_ref(sd_resolve
*resolve
) {
600 assert_return(resolve
, NULL
);
602 assert(resolve
->n_ref
>= 1);
608 _public_ sd_resolve
* sd_resolve_unref(sd_resolve
*resolve
) {
613 assert(resolve
->n_ref
>= 1);
616 if (resolve
->n_ref
<= 0)
617 resolve_free(resolve
);
622 _public_
int sd_resolve_get_fd(sd_resolve
*resolve
) {
623 assert_return(resolve
, -EINVAL
);
624 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
626 return resolve
->fds
[RESPONSE_RECV_FD
];
629 _public_
int sd_resolve_get_events(sd_resolve
*resolve
) {
630 assert_return(resolve
, -EINVAL
);
631 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
633 return resolve
->n_queries
> resolve
->n_done
? POLLIN
: 0;
636 _public_
int sd_resolve_get_timeout(sd_resolve
*resolve
, uint64_t *usec
) {
637 assert_return(resolve
, -EINVAL
);
638 assert_return(usec
, -EINVAL
);
639 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
641 *usec
= (uint64_t) -1;
645 static sd_resolve_query
*lookup_query(sd_resolve
*resolve
, unsigned id
) {
650 q
= resolve
->query_array
[id
% QUERIES_MAX
];
658 static int complete_query(sd_resolve
*resolve
, sd_resolve_query
*q
) {
663 assert(q
->resolve
== resolve
);
668 resolve
->current
= sd_resolve_query_ref(q
);
672 case REQUEST_ADDRINFO
:
673 r
= getaddrinfo_done(q
);
676 case REQUEST_NAMEINFO
:
677 r
= getnameinfo_done(q
);
681 assert_not_reached("Cannot complete unknown query type");
684 resolve
->current
= NULL
;
687 resolve_query_disconnect(q
);
688 sd_resolve_query_unref(q
);
691 sd_resolve_query_unref(q
);
696 static int unserialize_addrinfo(const void **p
, size_t *length
, struct addrinfo
**ret_ai
) {
697 AddrInfoSerialization s
;
706 if (*length
< sizeof(AddrInfoSerialization
))
709 memcpy(&s
, *p
, sizeof(s
));
711 l
= sizeof(AddrInfoSerialization
) + s
.ai_addrlen
+ s
.canonname_len
;
715 ai
= new0(struct addrinfo
, 1);
719 ai
->ai_flags
= s
.ai_flags
;
720 ai
->ai_family
= s
.ai_family
;
721 ai
->ai_socktype
= s
.ai_socktype
;
722 ai
->ai_protocol
= s
.ai_protocol
;
723 ai
->ai_addrlen
= s
.ai_addrlen
;
725 if (s
.ai_addrlen
> 0) {
726 ai
->ai_addr
= memdup((const uint8_t*) *p
+ sizeof(AddrInfoSerialization
), s
.ai_addrlen
);
733 if (s
.canonname_len
> 0) {
734 ai
->ai_canonname
= memdup((const uint8_t*) *p
+ sizeof(AddrInfoSerialization
) + s
.ai_addrlen
, s
.canonname_len
);
735 if (!ai
->ai_canonname
) {
744 *p
= ((const uint8_t*) *p
) + l
;
749 static int handle_response(sd_resolve
*resolve
, const Packet
*packet
, size_t length
) {
756 resp
= &packet
->rheader
;
758 assert(length
>= sizeof(RHeader
));
759 assert(length
== resp
->length
);
761 if (resp
->type
== RESPONSE_DIED
) {
762 resolve
->dead
= true;
766 assert(resolve
->n_outstanding
> 0);
767 resolve
->n_outstanding
--;
769 q
= lookup_query(resolve
, resp
->id
);
773 switch (resp
->type
) {
775 case RESPONSE_ADDRINFO
: {
776 const AddrInfoResponse
*ai_resp
= &packet
->addrinfo_response
;
779 struct addrinfo
*prev
= NULL
;
781 assert(length
>= sizeof(AddrInfoResponse
));
782 assert(q
->type
== REQUEST_ADDRINFO
);
784 q
->ret
= ai_resp
->ret
;
785 q
->_errno
= ai_resp
->_errno
;
786 q
->_h_errno
= ai_resp
->_h_errno
;
788 l
= length
- sizeof(AddrInfoResponse
);
789 p
= (const uint8_t*) resp
+ sizeof(AddrInfoResponse
);
792 struct addrinfo
*ai
= NULL
;
794 r
= unserialize_addrinfo(&p
, &l
, &ai
);
799 freeaddrinfo(q
->addrinfo
);
812 return complete_query(resolve
, q
);
815 case RESPONSE_NAMEINFO
: {
816 const NameInfoResponse
*ni_resp
= &packet
->nameinfo_response
;
818 assert(length
>= sizeof(NameInfoResponse
));
819 assert(q
->type
== REQUEST_NAMEINFO
);
821 q
->ret
= ni_resp
->ret
;
822 q
->_errno
= ni_resp
->_errno
;
823 q
->_h_errno
= ni_resp
->_h_errno
;
825 if (ni_resp
->hostlen
> 0) {
826 q
->host
= strndup((const char*) ni_resp
+ sizeof(NameInfoResponse
), ni_resp
->hostlen
-1);
834 if (ni_resp
->servlen
> 0) {
835 q
->serv
= strndup((const char*) ni_resp
+ sizeof(NameInfoResponse
) + ni_resp
->hostlen
, ni_resp
->servlen
-1);
843 return complete_query(resolve
, q
);
851 _public_
int sd_resolve_process(sd_resolve
*resolve
) {
852 RESOLVE_DONT_DESTROY(resolve
);
856 uint8_t space
[BUFSIZE
];
861 assert_return(resolve
, -EINVAL
);
862 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
864 /* We don't allow recursively invoking sd_resolve_process(). */
865 assert_return(!resolve
->current
, -EBUSY
);
867 l
= recv(resolve
->fds
[RESPONSE_RECV_FD
], &buf
, sizeof(buf
), 0);
875 return -ECONNREFUSED
;
877 r
= handle_response(resolve
, &buf
.packet
, (size_t) l
);
884 _public_
int sd_resolve_wait(sd_resolve
*resolve
, uint64_t timeout_usec
) {
887 assert_return(resolve
, -EINVAL
);
888 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
890 if (resolve
->n_done
>= resolve
->n_queries
)
894 r
= fd_wait_for_event(resolve
->fds
[RESPONSE_RECV_FD
], POLLIN
, timeout_usec
);
895 } while (r
== -EINTR
);
900 return sd_resolve_process(resolve
);
903 static int alloc_query(sd_resolve
*resolve
, bool floating
, sd_resolve_query
**_q
) {
910 if (resolve
->n_queries
>= QUERIES_MAX
)
913 r
= start_threads(resolve
, 1);
917 while (resolve
->query_array
[resolve
->current_id
% QUERIES_MAX
])
918 resolve
->current_id
++;
920 q
= resolve
->query_array
[resolve
->current_id
% QUERIES_MAX
] = new0(sd_resolve_query
, 1);
925 q
->resolve
= resolve
;
926 q
->floating
= floating
;
927 q
->id
= resolve
->current_id
++;
930 sd_resolve_ref(resolve
);
932 LIST_PREPEND(queries
, resolve
->queries
, q
);
933 resolve
->n_queries
++;
939 _public_
int sd_resolve_getaddrinfo(
941 sd_resolve_query
**_q
,
942 const char *node
, const char *service
,
943 const struct addrinfo
*hints
,
944 sd_resolve_getaddrinfo_handler_t callback
, void *userdata
) {
946 AddrInfoRequest req
= {};
947 struct msghdr mh
= {};
952 assert_return(resolve
, -EINVAL
);
953 assert_return(node
|| service
, -EINVAL
);
954 assert_return(callback
, -EINVAL
);
955 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
957 r
= alloc_query(resolve
, !_q
, &q
);
961 q
->type
= REQUEST_ADDRINFO
;
962 q
->getaddrinfo_handler
= callback
;
963 q
->userdata
= userdata
;
965 req
.node_len
= node
? strlen(node
)+1 : 0;
966 req
.service_len
= service
? strlen(service
)+1 : 0;
968 req
.header
.id
= q
->id
;
969 req
.header
.type
= REQUEST_ADDRINFO
;
970 req
.header
.length
= sizeof(AddrInfoRequest
) + req
.node_len
+ req
.service_len
;
973 req
.hints_valid
= true;
974 req
.ai_flags
= hints
->ai_flags
;
975 req
.ai_family
= hints
->ai_family
;
976 req
.ai_socktype
= hints
->ai_socktype
;
977 req
.ai_protocol
= hints
->ai_protocol
;
980 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= &req
, .iov_len
= sizeof(AddrInfoRequest
) };
982 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= (void*) node
, .iov_len
= req
.node_len
};
984 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= (void*) service
, .iov_len
= req
.service_len
};
987 if (sendmsg(resolve
->fds
[REQUEST_SEND_FD
], &mh
, MSG_NOSIGNAL
) < 0) {
988 sd_resolve_query_unref(q
);
992 resolve
->n_outstanding
++;
1000 static int getaddrinfo_done(sd_resolve_query
* q
) {
1003 assert(q
->getaddrinfo_handler
);
1006 h_errno
= q
->_h_errno
;
1008 return q
->getaddrinfo_handler(q
, q
->ret
, q
->addrinfo
, q
->userdata
);
1011 _public_
int sd_resolve_getnameinfo(
1012 sd_resolve
*resolve
,
1013 sd_resolve_query
**_q
,
1014 const struct sockaddr
*sa
, socklen_t salen
,
1017 sd_resolve_getnameinfo_handler_t callback
,
1020 NameInfoRequest req
= {};
1021 struct msghdr mh
= {};
1022 struct iovec iov
[2];
1023 sd_resolve_query
*q
;
1026 assert_return(resolve
, -EINVAL
);
1027 assert_return(sa
, -EINVAL
);
1028 assert_return(salen
>= sizeof(struct sockaddr
), -EINVAL
);
1029 assert_return(salen
<= sizeof(union sockaddr_union
), -EINVAL
);
1030 assert_return((get
& ~SD_RESOLVE_GET_BOTH
) == 0, -EINVAL
);
1031 assert_return(callback
, -EINVAL
);
1032 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
1034 r
= alloc_query(resolve
, !_q
, &q
);
1038 q
->type
= REQUEST_NAMEINFO
;
1039 q
->getnameinfo_handler
= callback
;
1040 q
->userdata
= userdata
;
1042 req
.header
.id
= q
->id
;
1043 req
.header
.type
= REQUEST_NAMEINFO
;
1044 req
.header
.length
= sizeof(NameInfoRequest
) + salen
;
1047 req
.sockaddr_len
= salen
;
1048 req
.gethost
= !!(get
& SD_RESOLVE_GET_HOST
);
1049 req
.getserv
= !!(get
& SD_RESOLVE_GET_SERVICE
);
1051 iov
[0] = (struct iovec
) { .iov_base
= &req
, .iov_len
= sizeof(NameInfoRequest
) };
1052 iov
[1] = (struct iovec
) { .iov_base
= (void*) sa
, .iov_len
= salen
};
1057 if (sendmsg(resolve
->fds
[REQUEST_SEND_FD
], &mh
, MSG_NOSIGNAL
) < 0) {
1058 sd_resolve_query_unref(q
);
1062 resolve
->n_outstanding
++;
1070 static int getnameinfo_done(sd_resolve_query
*q
) {
1074 assert(q
->getnameinfo_handler
);
1077 h_errno
= q
->_h_errno
;
1079 return q
->getnameinfo_handler(q
, q
->ret
, q
->host
, q
->serv
, q
->userdata
);
1082 _public_ sd_resolve_query
* sd_resolve_query_ref(sd_resolve_query
*q
) {
1083 assert_return(q
, NULL
);
1085 assert(q
->n_ref
>= 1);
1091 static void resolve_freeaddrinfo(struct addrinfo
*ai
) {
1093 struct addrinfo
*next
= ai
->ai_next
;
1096 free(ai
->ai_canonname
);
1102 static void resolve_query_disconnect(sd_resolve_query
*q
) {
1103 sd_resolve
*resolve
;
1111 resolve
= q
->resolve
;
1112 assert(resolve
->n_queries
> 0);
1115 assert(resolve
->n_done
> 0);
1119 i
= q
->id
% QUERIES_MAX
;
1120 assert(resolve
->query_array
[i
] == q
);
1121 resolve
->query_array
[i
] = NULL
;
1122 LIST_REMOVE(queries
, resolve
->queries
, q
);
1123 resolve
->n_queries
--;
1127 sd_resolve_unref(resolve
);
1130 static void resolve_query_free(sd_resolve_query
*q
) {
1133 resolve_query_disconnect(q
);
1135 resolve_freeaddrinfo(q
->addrinfo
);
1141 _public_ sd_resolve_query
* sd_resolve_query_unref(sd_resolve_query
* q
) {
1145 assert(q
->n_ref
>= 1);
1149 resolve_query_free(q
);
1154 _public_
int sd_resolve_query_is_done(sd_resolve_query
*q
) {
1155 assert_return(q
, -EINVAL
);
1156 assert_return(!resolve_pid_changed(q
->resolve
), -ECHILD
);
1161 _public_
void* sd_resolve_query_set_userdata(sd_resolve_query
*q
, void *userdata
) {
1164 assert_return(q
, NULL
);
1165 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1168 q
->userdata
= userdata
;
1173 _public_
void* sd_resolve_query_get_userdata(sd_resolve_query
*q
) {
1174 assert_return(q
, NULL
);
1175 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1180 _public_ sd_resolve
*sd_resolve_query_get_resolve(sd_resolve_query
*q
) {
1181 assert_return(q
, NULL
);
1182 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1187 static int io_callback(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
1188 sd_resolve
*resolve
= userdata
;
1193 r
= sd_resolve_process(resolve
);
1200 _public_
int sd_resolve_attach_event(sd_resolve
*resolve
, sd_event
*event
, int priority
) {
1203 assert_return(resolve
, -EINVAL
);
1204 assert_return(!resolve
->event
, -EBUSY
);
1206 assert(!resolve
->event_source
);
1209 resolve
->event
= sd_event_ref(event
);
1211 r
= sd_event_default(&resolve
->event
);
1216 r
= sd_event_add_io(resolve
->event
, &resolve
->event_source
, resolve
->fds
[RESPONSE_RECV_FD
], POLLIN
, io_callback
, resolve
);
1220 r
= sd_event_source_set_priority(resolve
->event_source
, priority
);
1227 sd_resolve_detach_event(resolve
);
1231 _public_
int sd_resolve_detach_event(sd_resolve
*resolve
) {
1232 assert_return(resolve
, -EINVAL
);
1234 if (!resolve
->event
)
1237 if (resolve
->event_source
) {
1238 sd_event_source_set_enabled(resolve
->event_source
, SD_EVENT_OFF
);
1239 resolve
->event_source
= sd_event_source_unref(resolve
->event_source
);
1242 resolve
->event
= sd_event_unref(resolve
->event
);
1246 _public_ sd_event
*sd_resolve_get_event(sd_resolve
*resolve
) {
1247 assert_return(resolve
, NULL
);
1249 return resolve
->event
;