2 This file is part of systemd.
4 Copyright 2005-2008 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
29 #include <sys/prctl.h>
32 #include "sd-resolve.h"
34 #include "alloc-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_(sd_resolve_unrefp) _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
++)
585 pthread_join(resolve
->workers
[i
], NULL
);
587 /* Close all communication channels */
588 for (i
= 0; i
< _FD_MAX
; i
++)
589 safe_close(resolve
->fds
[i
]);
594 _public_ sd_resolve
* sd_resolve_ref(sd_resolve
*resolve
) {
595 assert_return(resolve
, NULL
);
597 assert(resolve
->n_ref
>= 1);
603 _public_ sd_resolve
* sd_resolve_unref(sd_resolve
*resolve
) {
608 assert(resolve
->n_ref
>= 1);
611 if (resolve
->n_ref
<= 0)
612 resolve_free(resolve
);
617 _public_
int sd_resolve_get_fd(sd_resolve
*resolve
) {
618 assert_return(resolve
, -EINVAL
);
619 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
621 return resolve
->fds
[RESPONSE_RECV_FD
];
624 _public_
int sd_resolve_get_events(sd_resolve
*resolve
) {
625 assert_return(resolve
, -EINVAL
);
626 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
628 return resolve
->n_queries
> resolve
->n_done
? POLLIN
: 0;
631 _public_
int sd_resolve_get_timeout(sd_resolve
*resolve
, uint64_t *usec
) {
632 assert_return(resolve
, -EINVAL
);
633 assert_return(usec
, -EINVAL
);
634 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
636 *usec
= (uint64_t) -1;
640 static sd_resolve_query
*lookup_query(sd_resolve
*resolve
, unsigned id
) {
645 q
= resolve
->query_array
[id
% QUERIES_MAX
];
653 static int complete_query(sd_resolve
*resolve
, sd_resolve_query
*q
) {
658 assert(q
->resolve
== resolve
);
663 resolve
->current
= sd_resolve_query_ref(q
);
667 case REQUEST_ADDRINFO
:
668 r
= getaddrinfo_done(q
);
671 case REQUEST_NAMEINFO
:
672 r
= getnameinfo_done(q
);
676 assert_not_reached("Cannot complete unknown query type");
679 resolve
->current
= NULL
;
682 resolve_query_disconnect(q
);
683 sd_resolve_query_unref(q
);
686 sd_resolve_query_unref(q
);
691 static int unserialize_addrinfo(const void **p
, size_t *length
, struct addrinfo
**ret_ai
) {
692 AddrInfoSerialization s
;
701 if (*length
< sizeof(AddrInfoSerialization
))
704 memcpy(&s
, *p
, sizeof(s
));
706 l
= sizeof(AddrInfoSerialization
) + s
.ai_addrlen
+ s
.canonname_len
;
710 ai
= new0(struct addrinfo
, 1);
714 ai
->ai_flags
= s
.ai_flags
;
715 ai
->ai_family
= s
.ai_family
;
716 ai
->ai_socktype
= s
.ai_socktype
;
717 ai
->ai_protocol
= s
.ai_protocol
;
718 ai
->ai_addrlen
= s
.ai_addrlen
;
720 if (s
.ai_addrlen
> 0) {
721 ai
->ai_addr
= memdup((const uint8_t*) *p
+ sizeof(AddrInfoSerialization
), s
.ai_addrlen
);
728 if (s
.canonname_len
> 0) {
729 ai
->ai_canonname
= memdup((const uint8_t*) *p
+ sizeof(AddrInfoSerialization
) + s
.ai_addrlen
, s
.canonname_len
);
730 if (!ai
->ai_canonname
) {
739 *p
= ((const uint8_t*) *p
) + l
;
744 static int handle_response(sd_resolve
*resolve
, const Packet
*packet
, size_t length
) {
751 resp
= &packet
->rheader
;
753 assert(length
>= sizeof(RHeader
));
754 assert(length
== resp
->length
);
756 if (resp
->type
== RESPONSE_DIED
) {
757 resolve
->dead
= true;
761 assert(resolve
->n_outstanding
> 0);
762 resolve
->n_outstanding
--;
764 q
= lookup_query(resolve
, resp
->id
);
768 switch (resp
->type
) {
770 case RESPONSE_ADDRINFO
: {
771 const AddrInfoResponse
*ai_resp
= &packet
->addrinfo_response
;
774 struct addrinfo
*prev
= NULL
;
776 assert(length
>= sizeof(AddrInfoResponse
));
777 assert(q
->type
== REQUEST_ADDRINFO
);
779 q
->ret
= ai_resp
->ret
;
780 q
->_errno
= ai_resp
->_errno
;
781 q
->_h_errno
= ai_resp
->_h_errno
;
783 l
= length
- sizeof(AddrInfoResponse
);
784 p
= (const uint8_t*) resp
+ sizeof(AddrInfoResponse
);
787 struct addrinfo
*ai
= NULL
;
789 r
= unserialize_addrinfo(&p
, &l
, &ai
);
794 freeaddrinfo(q
->addrinfo
);
807 return complete_query(resolve
, q
);
810 case RESPONSE_NAMEINFO
: {
811 const NameInfoResponse
*ni_resp
= &packet
->nameinfo_response
;
813 assert(length
>= sizeof(NameInfoResponse
));
814 assert(q
->type
== REQUEST_NAMEINFO
);
816 q
->ret
= ni_resp
->ret
;
817 q
->_errno
= ni_resp
->_errno
;
818 q
->_h_errno
= ni_resp
->_h_errno
;
820 if (ni_resp
->hostlen
> 0) {
821 q
->host
= strndup((const char*) ni_resp
+ sizeof(NameInfoResponse
), ni_resp
->hostlen
-1);
829 if (ni_resp
->servlen
> 0) {
830 q
->serv
= strndup((const char*) ni_resp
+ sizeof(NameInfoResponse
) + ni_resp
->hostlen
, ni_resp
->servlen
-1);
838 return complete_query(resolve
, q
);
846 _public_
int sd_resolve_process(sd_resolve
*resolve
) {
847 RESOLVE_DONT_DESTROY(resolve
);
851 uint8_t space
[BUFSIZE
];
856 assert_return(resolve
, -EINVAL
);
857 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
859 /* We don't allow recursively invoking sd_resolve_process(). */
860 assert_return(!resolve
->current
, -EBUSY
);
862 l
= recv(resolve
->fds
[RESPONSE_RECV_FD
], &buf
, sizeof(buf
), 0);
870 return -ECONNREFUSED
;
872 r
= handle_response(resolve
, &buf
.packet
, (size_t) l
);
879 _public_
int sd_resolve_wait(sd_resolve
*resolve
, uint64_t timeout_usec
) {
882 assert_return(resolve
, -EINVAL
);
883 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
885 if (resolve
->n_done
>= resolve
->n_queries
)
889 r
= fd_wait_for_event(resolve
->fds
[RESPONSE_RECV_FD
], POLLIN
, timeout_usec
);
890 } while (r
== -EINTR
);
895 return sd_resolve_process(resolve
);
898 static int alloc_query(sd_resolve
*resolve
, bool floating
, sd_resolve_query
**_q
) {
905 if (resolve
->n_queries
>= QUERIES_MAX
)
908 r
= start_threads(resolve
, 1);
912 while (resolve
->query_array
[resolve
->current_id
% QUERIES_MAX
])
913 resolve
->current_id
++;
915 q
= resolve
->query_array
[resolve
->current_id
% QUERIES_MAX
] = new0(sd_resolve_query
, 1);
920 q
->resolve
= resolve
;
921 q
->floating
= floating
;
922 q
->id
= resolve
->current_id
++;
925 sd_resolve_ref(resolve
);
927 LIST_PREPEND(queries
, resolve
->queries
, q
);
928 resolve
->n_queries
++;
934 _public_
int sd_resolve_getaddrinfo(
936 sd_resolve_query
**_q
,
937 const char *node
, const char *service
,
938 const struct addrinfo
*hints
,
939 sd_resolve_getaddrinfo_handler_t callback
, void *userdata
) {
941 AddrInfoRequest req
= {};
942 struct msghdr mh
= {};
947 assert_return(resolve
, -EINVAL
);
948 assert_return(node
|| service
, -EINVAL
);
949 assert_return(callback
, -EINVAL
);
950 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
952 r
= alloc_query(resolve
, !_q
, &q
);
956 q
->type
= REQUEST_ADDRINFO
;
957 q
->getaddrinfo_handler
= callback
;
958 q
->userdata
= userdata
;
960 req
.node_len
= node
? strlen(node
)+1 : 0;
961 req
.service_len
= service
? strlen(service
)+1 : 0;
963 req
.header
.id
= q
->id
;
964 req
.header
.type
= REQUEST_ADDRINFO
;
965 req
.header
.length
= sizeof(AddrInfoRequest
) + req
.node_len
+ req
.service_len
;
968 req
.hints_valid
= true;
969 req
.ai_flags
= hints
->ai_flags
;
970 req
.ai_family
= hints
->ai_family
;
971 req
.ai_socktype
= hints
->ai_socktype
;
972 req
.ai_protocol
= hints
->ai_protocol
;
975 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= &req
, .iov_len
= sizeof(AddrInfoRequest
) };
977 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= (void*) node
, .iov_len
= req
.node_len
};
979 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= (void*) service
, .iov_len
= req
.service_len
};
982 if (sendmsg(resolve
->fds
[REQUEST_SEND_FD
], &mh
, MSG_NOSIGNAL
) < 0) {
983 sd_resolve_query_unref(q
);
987 resolve
->n_outstanding
++;
995 static int getaddrinfo_done(sd_resolve_query
* q
) {
998 assert(q
->getaddrinfo_handler
);
1001 h_errno
= q
->_h_errno
;
1003 return q
->getaddrinfo_handler(q
, q
->ret
, q
->addrinfo
, q
->userdata
);
1006 _public_
int sd_resolve_getnameinfo(
1007 sd_resolve
*resolve
,
1008 sd_resolve_query
**_q
,
1009 const struct sockaddr
*sa
, socklen_t salen
,
1012 sd_resolve_getnameinfo_handler_t callback
,
1015 NameInfoRequest req
= {};
1016 struct msghdr mh
= {};
1017 struct iovec iov
[2];
1018 sd_resolve_query
*q
;
1021 assert_return(resolve
, -EINVAL
);
1022 assert_return(sa
, -EINVAL
);
1023 assert_return(salen
>= sizeof(struct sockaddr
), -EINVAL
);
1024 assert_return(salen
<= sizeof(union sockaddr_union
), -EINVAL
);
1025 assert_return((get
& ~SD_RESOLVE_GET_BOTH
) == 0, -EINVAL
);
1026 assert_return(callback
, -EINVAL
);
1027 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
1029 r
= alloc_query(resolve
, !_q
, &q
);
1033 q
->type
= REQUEST_NAMEINFO
;
1034 q
->getnameinfo_handler
= callback
;
1035 q
->userdata
= userdata
;
1037 req
.header
.id
= q
->id
;
1038 req
.header
.type
= REQUEST_NAMEINFO
;
1039 req
.header
.length
= sizeof(NameInfoRequest
) + salen
;
1042 req
.sockaddr_len
= salen
;
1043 req
.gethost
= !!(get
& SD_RESOLVE_GET_HOST
);
1044 req
.getserv
= !!(get
& SD_RESOLVE_GET_SERVICE
);
1046 iov
[0] = (struct iovec
) { .iov_base
= &req
, .iov_len
= sizeof(NameInfoRequest
) };
1047 iov
[1] = (struct iovec
) { .iov_base
= (void*) sa
, .iov_len
= salen
};
1052 if (sendmsg(resolve
->fds
[REQUEST_SEND_FD
], &mh
, MSG_NOSIGNAL
) < 0) {
1053 sd_resolve_query_unref(q
);
1057 resolve
->n_outstanding
++;
1065 static int getnameinfo_done(sd_resolve_query
*q
) {
1069 assert(q
->getnameinfo_handler
);
1072 h_errno
= q
->_h_errno
;
1074 return q
->getnameinfo_handler(q
, q
->ret
, q
->host
, q
->serv
, q
->userdata
);
1077 _public_ sd_resolve_query
* sd_resolve_query_ref(sd_resolve_query
*q
) {
1078 assert_return(q
, NULL
);
1080 assert(q
->n_ref
>= 1);
1086 static void resolve_freeaddrinfo(struct addrinfo
*ai
) {
1088 struct addrinfo
*next
= ai
->ai_next
;
1091 free(ai
->ai_canonname
);
1097 static void resolve_query_disconnect(sd_resolve_query
*q
) {
1098 sd_resolve
*resolve
;
1106 resolve
= q
->resolve
;
1107 assert(resolve
->n_queries
> 0);
1110 assert(resolve
->n_done
> 0);
1114 i
= q
->id
% QUERIES_MAX
;
1115 assert(resolve
->query_array
[i
] == q
);
1116 resolve
->query_array
[i
] = NULL
;
1117 LIST_REMOVE(queries
, resolve
->queries
, q
);
1118 resolve
->n_queries
--;
1122 sd_resolve_unref(resolve
);
1125 static void resolve_query_free(sd_resolve_query
*q
) {
1128 resolve_query_disconnect(q
);
1130 resolve_freeaddrinfo(q
->addrinfo
);
1136 _public_ sd_resolve_query
* sd_resolve_query_unref(sd_resolve_query
* q
) {
1140 assert(q
->n_ref
>= 1);
1144 resolve_query_free(q
);
1149 _public_
int sd_resolve_query_is_done(sd_resolve_query
*q
) {
1150 assert_return(q
, -EINVAL
);
1151 assert_return(!resolve_pid_changed(q
->resolve
), -ECHILD
);
1156 _public_
void* sd_resolve_query_set_userdata(sd_resolve_query
*q
, void *userdata
) {
1159 assert_return(q
, NULL
);
1160 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1163 q
->userdata
= userdata
;
1168 _public_
void* sd_resolve_query_get_userdata(sd_resolve_query
*q
) {
1169 assert_return(q
, NULL
);
1170 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1175 _public_ sd_resolve
*sd_resolve_query_get_resolve(sd_resolve_query
*q
) {
1176 assert_return(q
, NULL
);
1177 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1182 static int io_callback(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
1183 sd_resolve
*resolve
= userdata
;
1188 r
= sd_resolve_process(resolve
);
1195 _public_
int sd_resolve_attach_event(sd_resolve
*resolve
, sd_event
*event
, int priority
) {
1198 assert_return(resolve
, -EINVAL
);
1199 assert_return(!resolve
->event
, -EBUSY
);
1201 assert(!resolve
->event_source
);
1204 resolve
->event
= sd_event_ref(event
);
1206 r
= sd_event_default(&resolve
->event
);
1211 r
= sd_event_add_io(resolve
->event
, &resolve
->event_source
, resolve
->fds
[RESPONSE_RECV_FD
], POLLIN
, io_callback
, resolve
);
1215 r
= sd_event_source_set_priority(resolve
->event_source
, priority
);
1222 sd_resolve_detach_event(resolve
);
1226 _public_
int sd_resolve_detach_event(sd_resolve
*resolve
) {
1227 assert_return(resolve
, -EINVAL
);
1229 if (!resolve
->event
)
1232 if (resolve
->event_source
) {
1233 sd_event_source_set_enabled(resolve
->event_source
, SD_EVENT_OFF
);
1234 resolve
->event_source
= sd_event_source_unref(resolve
->event_source
);
1237 resolve
->event
= sd_event_unref(resolve
->event
);
1241 _public_ sd_event
*sd_resolve_get_event(sd_resolve
*resolve
) {
1242 assert_return(resolve
, NULL
);
1244 return resolve
->event
;