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 "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_(sd_resolve_unrefp) _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
++)
587 pthread_join(resolve
->workers
[i
], NULL
);
589 /* Close all communication channels */
590 for (i
= 0; i
< _FD_MAX
; i
++)
591 safe_close(resolve
->fds
[i
]);
596 _public_ sd_resolve
* sd_resolve_ref(sd_resolve
*resolve
) {
597 assert_return(resolve
, NULL
);
599 assert(resolve
->n_ref
>= 1);
605 _public_ sd_resolve
* sd_resolve_unref(sd_resolve
*resolve
) {
610 assert(resolve
->n_ref
>= 1);
613 if (resolve
->n_ref
<= 0)
614 resolve_free(resolve
);
619 _public_
int sd_resolve_get_fd(sd_resolve
*resolve
) {
620 assert_return(resolve
, -EINVAL
);
621 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
623 return resolve
->fds
[RESPONSE_RECV_FD
];
626 _public_
int sd_resolve_get_events(sd_resolve
*resolve
) {
627 assert_return(resolve
, -EINVAL
);
628 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
630 return resolve
->n_queries
> resolve
->n_done
? POLLIN
: 0;
633 _public_
int sd_resolve_get_timeout(sd_resolve
*resolve
, uint64_t *usec
) {
634 assert_return(resolve
, -EINVAL
);
635 assert_return(usec
, -EINVAL
);
636 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
638 *usec
= (uint64_t) -1;
642 static sd_resolve_query
*lookup_query(sd_resolve
*resolve
, unsigned id
) {
647 q
= resolve
->query_array
[id
% QUERIES_MAX
];
655 static int complete_query(sd_resolve
*resolve
, sd_resolve_query
*q
) {
660 assert(q
->resolve
== resolve
);
665 resolve
->current
= sd_resolve_query_ref(q
);
669 case REQUEST_ADDRINFO
:
670 r
= getaddrinfo_done(q
);
673 case REQUEST_NAMEINFO
:
674 r
= getnameinfo_done(q
);
678 assert_not_reached("Cannot complete unknown query type");
681 resolve
->current
= NULL
;
684 resolve_query_disconnect(q
);
685 sd_resolve_query_unref(q
);
688 sd_resolve_query_unref(q
);
693 static int unserialize_addrinfo(const void **p
, size_t *length
, struct addrinfo
**ret_ai
) {
694 AddrInfoSerialization s
;
703 if (*length
< sizeof(AddrInfoSerialization
))
706 memcpy(&s
, *p
, sizeof(s
));
708 l
= sizeof(AddrInfoSerialization
) + s
.ai_addrlen
+ s
.canonname_len
;
712 ai
= new0(struct addrinfo
, 1);
716 ai
->ai_flags
= s
.ai_flags
;
717 ai
->ai_family
= s
.ai_family
;
718 ai
->ai_socktype
= s
.ai_socktype
;
719 ai
->ai_protocol
= s
.ai_protocol
;
720 ai
->ai_addrlen
= s
.ai_addrlen
;
722 if (s
.ai_addrlen
> 0) {
723 ai
->ai_addr
= memdup((const uint8_t*) *p
+ sizeof(AddrInfoSerialization
), s
.ai_addrlen
);
730 if (s
.canonname_len
> 0) {
731 ai
->ai_canonname
= memdup((const uint8_t*) *p
+ sizeof(AddrInfoSerialization
) + s
.ai_addrlen
, s
.canonname_len
);
732 if (!ai
->ai_canonname
) {
741 *p
= ((const uint8_t*) *p
) + l
;
746 static int handle_response(sd_resolve
*resolve
, const Packet
*packet
, size_t length
) {
753 resp
= &packet
->rheader
;
755 assert(length
>= sizeof(RHeader
));
756 assert(length
== resp
->length
);
758 if (resp
->type
== RESPONSE_DIED
) {
759 resolve
->dead
= true;
763 assert(resolve
->n_outstanding
> 0);
764 resolve
->n_outstanding
--;
766 q
= lookup_query(resolve
, resp
->id
);
770 switch (resp
->type
) {
772 case RESPONSE_ADDRINFO
: {
773 const AddrInfoResponse
*ai_resp
= &packet
->addrinfo_response
;
776 struct addrinfo
*prev
= NULL
;
778 assert(length
>= sizeof(AddrInfoResponse
));
779 assert(q
->type
== REQUEST_ADDRINFO
);
781 q
->ret
= ai_resp
->ret
;
782 q
->_errno
= ai_resp
->_errno
;
783 q
->_h_errno
= ai_resp
->_h_errno
;
785 l
= length
- sizeof(AddrInfoResponse
);
786 p
= (const uint8_t*) resp
+ sizeof(AddrInfoResponse
);
789 struct addrinfo
*ai
= NULL
;
791 r
= unserialize_addrinfo(&p
, &l
, &ai
);
796 freeaddrinfo(q
->addrinfo
);
809 return complete_query(resolve
, q
);
812 case RESPONSE_NAMEINFO
: {
813 const NameInfoResponse
*ni_resp
= &packet
->nameinfo_response
;
815 assert(length
>= sizeof(NameInfoResponse
));
816 assert(q
->type
== REQUEST_NAMEINFO
);
818 q
->ret
= ni_resp
->ret
;
819 q
->_errno
= ni_resp
->_errno
;
820 q
->_h_errno
= ni_resp
->_h_errno
;
822 if (ni_resp
->hostlen
> 0) {
823 q
->host
= strndup((const char*) ni_resp
+ sizeof(NameInfoResponse
), ni_resp
->hostlen
-1);
831 if (ni_resp
->servlen
> 0) {
832 q
->serv
= strndup((const char*) ni_resp
+ sizeof(NameInfoResponse
) + ni_resp
->hostlen
, ni_resp
->servlen
-1);
840 return complete_query(resolve
, q
);
848 _public_
int sd_resolve_process(sd_resolve
*resolve
) {
849 RESOLVE_DONT_DESTROY(resolve
);
853 uint8_t space
[BUFSIZE
];
858 assert_return(resolve
, -EINVAL
);
859 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
861 /* We don't allow recursively invoking sd_resolve_process(). */
862 assert_return(!resolve
->current
, -EBUSY
);
864 l
= recv(resolve
->fds
[RESPONSE_RECV_FD
], &buf
, sizeof(buf
), 0);
872 return -ECONNREFUSED
;
874 r
= handle_response(resolve
, &buf
.packet
, (size_t) l
);
881 _public_
int sd_resolve_wait(sd_resolve
*resolve
, uint64_t timeout_usec
) {
884 assert_return(resolve
, -EINVAL
);
885 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
887 if (resolve
->n_done
>= resolve
->n_queries
)
891 r
= fd_wait_for_event(resolve
->fds
[RESPONSE_RECV_FD
], POLLIN
, timeout_usec
);
892 } while (r
== -EINTR
);
897 return sd_resolve_process(resolve
);
900 static int alloc_query(sd_resolve
*resolve
, bool floating
, sd_resolve_query
**_q
) {
907 if (resolve
->n_queries
>= QUERIES_MAX
)
910 r
= start_threads(resolve
, 1);
914 while (resolve
->query_array
[resolve
->current_id
% QUERIES_MAX
])
915 resolve
->current_id
++;
917 q
= resolve
->query_array
[resolve
->current_id
% QUERIES_MAX
] = new0(sd_resolve_query
, 1);
922 q
->resolve
= resolve
;
923 q
->floating
= floating
;
924 q
->id
= resolve
->current_id
++;
927 sd_resolve_ref(resolve
);
929 LIST_PREPEND(queries
, resolve
->queries
, q
);
930 resolve
->n_queries
++;
936 _public_
int sd_resolve_getaddrinfo(
938 sd_resolve_query
**_q
,
939 const char *node
, const char *service
,
940 const struct addrinfo
*hints
,
941 sd_resolve_getaddrinfo_handler_t callback
, void *userdata
) {
943 AddrInfoRequest req
= {};
944 struct msghdr mh
= {};
949 assert_return(resolve
, -EINVAL
);
950 assert_return(node
|| service
, -EINVAL
);
951 assert_return(callback
, -EINVAL
);
952 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
954 r
= alloc_query(resolve
, !_q
, &q
);
958 q
->type
= REQUEST_ADDRINFO
;
959 q
->getaddrinfo_handler
= callback
;
960 q
->userdata
= userdata
;
962 req
.node_len
= node
? strlen(node
)+1 : 0;
963 req
.service_len
= service
? strlen(service
)+1 : 0;
965 req
.header
.id
= q
->id
;
966 req
.header
.type
= REQUEST_ADDRINFO
;
967 req
.header
.length
= sizeof(AddrInfoRequest
) + req
.node_len
+ req
.service_len
;
970 req
.hints_valid
= true;
971 req
.ai_flags
= hints
->ai_flags
;
972 req
.ai_family
= hints
->ai_family
;
973 req
.ai_socktype
= hints
->ai_socktype
;
974 req
.ai_protocol
= hints
->ai_protocol
;
977 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= &req
, .iov_len
= sizeof(AddrInfoRequest
) };
979 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= (void*) node
, .iov_len
= req
.node_len
};
981 iov
[mh
.msg_iovlen
++] = (struct iovec
) { .iov_base
= (void*) service
, .iov_len
= req
.service_len
};
984 if (sendmsg(resolve
->fds
[REQUEST_SEND_FD
], &mh
, MSG_NOSIGNAL
) < 0) {
985 sd_resolve_query_unref(q
);
989 resolve
->n_outstanding
++;
997 static int getaddrinfo_done(sd_resolve_query
* q
) {
1000 assert(q
->getaddrinfo_handler
);
1003 h_errno
= q
->_h_errno
;
1005 return q
->getaddrinfo_handler(q
, q
->ret
, q
->addrinfo
, q
->userdata
);
1008 _public_
int sd_resolve_getnameinfo(
1009 sd_resolve
*resolve
,
1010 sd_resolve_query
**_q
,
1011 const struct sockaddr
*sa
, socklen_t salen
,
1014 sd_resolve_getnameinfo_handler_t callback
,
1017 NameInfoRequest req
= {};
1018 struct msghdr mh
= {};
1019 struct iovec iov
[2];
1020 sd_resolve_query
*q
;
1023 assert_return(resolve
, -EINVAL
);
1024 assert_return(sa
, -EINVAL
);
1025 assert_return(salen
>= sizeof(struct sockaddr
), -EINVAL
);
1026 assert_return(salen
<= sizeof(union sockaddr_union
), -EINVAL
);
1027 assert_return((get
& ~SD_RESOLVE_GET_BOTH
) == 0, -EINVAL
);
1028 assert_return(callback
, -EINVAL
);
1029 assert_return(!resolve_pid_changed(resolve
), -ECHILD
);
1031 r
= alloc_query(resolve
, !_q
, &q
);
1035 q
->type
= REQUEST_NAMEINFO
;
1036 q
->getnameinfo_handler
= callback
;
1037 q
->userdata
= userdata
;
1039 req
.header
.id
= q
->id
;
1040 req
.header
.type
= REQUEST_NAMEINFO
;
1041 req
.header
.length
= sizeof(NameInfoRequest
) + salen
;
1044 req
.sockaddr_len
= salen
;
1045 req
.gethost
= !!(get
& SD_RESOLVE_GET_HOST
);
1046 req
.getserv
= !!(get
& SD_RESOLVE_GET_SERVICE
);
1048 iov
[0] = (struct iovec
) { .iov_base
= &req
, .iov_len
= sizeof(NameInfoRequest
) };
1049 iov
[1] = (struct iovec
) { .iov_base
= (void*) sa
, .iov_len
= salen
};
1054 if (sendmsg(resolve
->fds
[REQUEST_SEND_FD
], &mh
, MSG_NOSIGNAL
) < 0) {
1055 sd_resolve_query_unref(q
);
1059 resolve
->n_outstanding
++;
1067 static int getnameinfo_done(sd_resolve_query
*q
) {
1071 assert(q
->getnameinfo_handler
);
1074 h_errno
= q
->_h_errno
;
1076 return q
->getnameinfo_handler(q
, q
->ret
, q
->host
, q
->serv
, q
->userdata
);
1079 _public_ sd_resolve_query
* sd_resolve_query_ref(sd_resolve_query
*q
) {
1080 assert_return(q
, NULL
);
1082 assert(q
->n_ref
>= 1);
1088 static void resolve_freeaddrinfo(struct addrinfo
*ai
) {
1090 struct addrinfo
*next
= ai
->ai_next
;
1093 free(ai
->ai_canonname
);
1099 static void resolve_query_disconnect(sd_resolve_query
*q
) {
1100 sd_resolve
*resolve
;
1108 resolve
= q
->resolve
;
1109 assert(resolve
->n_queries
> 0);
1112 assert(resolve
->n_done
> 0);
1116 i
= q
->id
% QUERIES_MAX
;
1117 assert(resolve
->query_array
[i
] == q
);
1118 resolve
->query_array
[i
] = NULL
;
1119 LIST_REMOVE(queries
, resolve
->queries
, q
);
1120 resolve
->n_queries
--;
1124 sd_resolve_unref(resolve
);
1127 static void resolve_query_free(sd_resolve_query
*q
) {
1130 resolve_query_disconnect(q
);
1132 resolve_freeaddrinfo(q
->addrinfo
);
1138 _public_ sd_resolve_query
* sd_resolve_query_unref(sd_resolve_query
* q
) {
1142 assert(q
->n_ref
>= 1);
1146 resolve_query_free(q
);
1151 _public_
int sd_resolve_query_is_done(sd_resolve_query
*q
) {
1152 assert_return(q
, -EINVAL
);
1153 assert_return(!resolve_pid_changed(q
->resolve
), -ECHILD
);
1158 _public_
void* sd_resolve_query_set_userdata(sd_resolve_query
*q
, void *userdata
) {
1161 assert_return(q
, NULL
);
1162 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1165 q
->userdata
= userdata
;
1170 _public_
void* sd_resolve_query_get_userdata(sd_resolve_query
*q
) {
1171 assert_return(q
, NULL
);
1172 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1177 _public_ sd_resolve
*sd_resolve_query_get_resolve(sd_resolve_query
*q
) {
1178 assert_return(q
, NULL
);
1179 assert_return(!resolve_pid_changed(q
->resolve
), NULL
);
1184 static int io_callback(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
1185 sd_resolve
*resolve
= userdata
;
1190 r
= sd_resolve_process(resolve
);
1197 _public_
int sd_resolve_attach_event(sd_resolve
*resolve
, sd_event
*event
, int priority
) {
1200 assert_return(resolve
, -EINVAL
);
1201 assert_return(!resolve
->event
, -EBUSY
);
1203 assert(!resolve
->event_source
);
1206 resolve
->event
= sd_event_ref(event
);
1208 r
= sd_event_default(&resolve
->event
);
1213 r
= sd_event_add_io(resolve
->event
, &resolve
->event_source
, resolve
->fds
[RESPONSE_RECV_FD
], POLLIN
, io_callback
, resolve
);
1217 r
= sd_event_source_set_priority(resolve
->event_source
, priority
);
1224 sd_resolve_detach_event(resolve
);
1228 _public_
int sd_resolve_detach_event(sd_resolve
*resolve
) {
1229 assert_return(resolve
, -EINVAL
);
1231 if (!resolve
->event
)
1234 if (resolve
->event_source
) {
1235 sd_event_source_set_enabled(resolve
->event_source
, SD_EVENT_OFF
);
1236 resolve
->event_source
= sd_event_source_unref(resolve
->event_source
);
1239 resolve
->event
= sd_event_unref(resolve
->event
);
1243 _public_ sd_event
*sd_resolve_get_event(sd_resolve
*resolve
) {
1244 assert_return(resolve
, NULL
);
1246 return resolve
->event
;