2 * Copyright (c) 2019 Apple Inc. All rights reserved.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "dnssd_private.h"
19 #include "dnssd_object.h"
20 #include "dnssd_xpc.h"
22 #include <CoreUtils/CoreUtils.h>
23 #include <os/object_private.h>
24 #include <xpc/private.h>
27 //======================================================================================================================
28 #pragma mark - Kind Declarations
31 #define DNSSD_STRUCT(NAME) struct dnssd_ ## NAME ## _s
32 #define DNSSD_TYPE(NAME) dnssd_ ## NAME ## _t
34 #define DNSSD_KIND_DECLARE(NAME) \
35 static DNSSD_TYPE(NAME) \
36 _dnssd_ ## NAME ## _alloc(void); \
39 _dnssd_ ## NAME ## _copy_description(DNSSD_TYPE(NAME) object, bool debug, bool privacy); \
42 _dnssd_ ## NAME ## _finalize(DNSSD_TYPE(NAME) object)
44 // Note: The last check checks if the base's type is equal to that of the superkind. If it's not, then the pointer
45 // comparison used as the argument to sizeof will cause a "comparison of distinct pointer types" warning, so long as
46 // the warning hasn't been disabled.
48 #define DNSSD_BASE_CHECK(NAME, SUPER) \
49 check_compile_time(offsetof(DNSSD_STRUCT(NAME), base) == 0); \
50 check_compile_time(sizeof_field(DNSSD_STRUCT(NAME), base) == sizeof(DNSSD_STRUCT(SUPER))); \
51 extern int _dnssd_base_type_check[sizeof(&(((DNSSD_TYPE(NAME))0)->base) == ((DNSSD_TYPE(SUPER))0))]
53 #define DNSSD_KIND_DEFINE(NAME, SUPER) \
54 static const struct dnssd_kind_s _dnssd_ ## NAME ## _kind = { \
55 &_dnssd_ ## SUPER ## _kind, \
57 _dnssd_ ## NAME ## _copy_description, \
58 _dnssd_ ## NAME ## _finalize, \
61 static DNSSD_TYPE(NAME) \
62 _dnssd_ ## NAME ## _alloc(void) \
64 DNSSD_TYPE(NAME) obj = dnssd_object_ ## NAME ## _alloc(sizeof(*obj)); \
65 require_quiet(obj, exit); \
67 const dnssd_object_t base = (dnssd_object_t)obj; \
68 base->kind = &_dnssd_ ## NAME ## _kind; \
73 DNSSD_BASE_CHECK(NAME, SUPER)
75 DNSSD_KIND_DECLARE(getaddrinfo
);
76 DNSSD_KIND_DECLARE(getaddrinfo_result
);
78 typedef char * (*dnssd_copy_description_f
)(dnssd_any_t object
, bool debug
, bool privacy
);
79 typedef void (*dnssd_finalize_f
)(dnssd_any_t object
);
81 typedef const struct dnssd_kind_s
* dnssd_kind_t
;
83 dnssd_kind_t superkind
; // This kind's superkind.
84 const char * name
; // Name of this kind.
85 dnssd_copy_description_f copy_description
; // Creates a textual description of object.
86 dnssd_finalize_f finalize
; // Releases object's resources right before the object is freed.
90 //======================================================================================================================
91 #pragma mark - dnssd_object Kind Definition
94 struct dnssd_object_s
{
95 _OS_OBJECT_HEADER(const void *_os_obj_isa
, _os_obj_refcnt
, _os_obj_xref_cnt
);
96 dnssd_kind_t kind
; // Pointer to an object's kind.
99 static const struct dnssd_kind_s _dnssd_object_kind
= {
100 NULL
, // No superkind.
102 NULL
, // No copy_description method.
103 NULL
, // No finalize method.
107 //======================================================================================================================
108 #pragma mark - dnssd_getaddrinfo Kind Definition
112 dnssd_getaddrinfo_state_nascent
= 0,
113 dnssd_getaddrinfo_state_starting
= 1,
114 dnssd_getaddrinfo_state_started
= 2,
115 dnssd_getaddrinfo_state_failed
= 3,
116 dnssd_getaddrinfo_state_invalidated
= 4,
117 } dnssd_getaddrinfo_state_t
;
119 struct dnssd_getaddrinfo_s
{
120 struct dnssd_object_s base
; // Object base.
121 dnssd_getaddrinfo_t next
; // Next getaddrinfo object in list.
122 uint64_t command_id
; // Command ID.
123 dispatch_queue_t user_queue
; // User's dispatch queue for invoking result and event handlers.
124 dispatch_queue_t mutex_queue
; // Mutex for accessing result_list from different queues.
125 xpc_object_t params
; // Parameters dictionary for getaddrinfo command.
126 xpc_object_t hostname
; // Reference to hostname from parameters dictionary.
127 dispatch_source_t event_source
; // Data source for triggering result and event handlers.
128 dnssd_getaddrinfo_result_t result_list
; // List of getaddrinfo results.
129 dnssd_getaddrinfo_result_handler_t result_handler
; // User's result handler.
130 dnssd_event_handler_t event_handler
; // User's event handler.
131 dnssd_getaddrinfo_state_t state
; // Internal state.
132 OSStatus error
; // Pending error.
133 bool user_activated
; // True if the object has been activated by user.
136 DNSSD_KIND_DEFINE(getaddrinfo
, object
);
139 //======================================================================================================================
140 #pragma mark - dnssd_getaddrinfo_result Kind Definition
143 struct dnssd_getaddrinfo_result_s
{
144 struct dnssd_object_s base
; // Object base.
145 sockaddr_ip addr
; // IPv4 or IPv6 address of hostname.
146 xpc_object_t hostname
; // Requested hostname to resolve.
147 xpc_object_t actual_hostname
; // The actual/canonical hostname of the requested hostname.
148 xpc_object_t auth_tag
; // Authentication tag.
149 uint32_t interface_index
; // Interface index to which the result pertains.
150 dnssd_getaddrinfo_result_type_t type
; // Type of getaddrinfo result.
151 dnssd_getaddrinfo_result_t next
; // Next getaddrinfo result in list.
154 DNSSD_KIND_DEFINE(getaddrinfo_result
, object
);
157 //======================================================================================================================
158 #pragma mark - Constants
161 #define DNSSD_EVENT_HAVE_RESULTS (1U << 0) // Results are available.
162 #define DNSSD_EVENT_REMOVE_ALL (1U << 1) // Previously delivered results are no longer valid.
163 #define DNSSD_EVENT_ERROR (1U << 2) // An error was encountered.
165 // Strings for redacted description items.
167 #define DNSSD_REDACTED_HOSTNAME_STR "<redacted hostname>"
168 #define DNSSD_REDACTED_ACTUAL_HOSTNAME_STR "<redacted actual hostname>"
169 #define DNSSD_REDACTED_IPv4_ADDRESS_STR "<redacted IPv4 address>"
170 #define DNSSD_REDACTED_IPv6_ADDRESS_STR "<redacted IPv6 address>"
173 //======================================================================================================================
174 #pragma mark - Local Prototypes
177 static dispatch_queue_t
178 _dnssd_client_queue(void);
180 static xpc_connection_t
181 _dnssd_client_connection(void);
184 _dnssd_client_get_new_id(void);
187 _dnssd_client_activate_getaddrinfo_async(dnssd_getaddrinfo_t gai
);
190 _dnssd_client_register_getaddrinfo(dnssd_getaddrinfo_t gai
);
193 _dnssd_client_deregister_getaddrinfo(dnssd_getaddrinfo_t gai
);
196 _dnssd_client_send_getaddrinfo_command(dnssd_getaddrinfo_t gai
);
199 _dnssd_client_fail_getaddrinfo(dnssd_getaddrinfo_t gai
, OSStatus error
);
202 _dnssd_getaddrinfo_append_results(dnssd_getaddrinfo_t gai
, dnssd_getaddrinfo_result_t result_list
);
205 _dnssd_getaddrinfo_remove_all_results(dnssd_getaddrinfo_t gai
);
207 static dnssd_getaddrinfo_result_t
208 _dnssd_getaddrinfo_take_results(dnssd_getaddrinfo_t gai
);
211 _dnssd_getaddrinfo_post_error_event(dnssd_getaddrinfo_t gai
, OSStatus error
);
213 static dnssd_getaddrinfo_result_t
214 _dnssd_getaddrinfo_result_create_from_dictionary(xpc_object_t hostname
, xpc_object_t result_dict
, OSStatus
*out_error
);
216 static DNSServiceErrorType
217 _dnssd_osstatus_to_dns_service_error(OSStatus status
);
219 #if !defined(dnssd_release_null_safe)
220 #define dnssd_release_null_safe(X) \
228 #if !defined(dnssd_forget)
229 #define dnssd_forget(X) ForgetCustom(X, dnssd_release)
233 //======================================================================================================================
234 #pragma mark - dnssd_object Public Methods
238 dnssd_retain(dnssd_any_t object
)
240 os_retain(object
.base
);
243 //======================================================================================================================
246 dnssd_release(dnssd_any_t object
)
248 os_release(object
.base
);
251 //======================================================================================================================
254 dnssd_copy_description(dnssd_any_t object
)
256 return dnssd_object_copy_description(object
, false, false);
260 //======================================================================================================================
261 #pragma mark - dnssd_object Private Methods
265 dnssd_object_copy_description(dnssd_any_t object
, bool debug
, bool privacy
)
267 for (dnssd_kind_t kind
= object
.base
->kind
; kind
; kind
= kind
->superkind
) {
268 if (kind
->copy_description
) {
269 char *desc
= kind
->copy_description(object
, debug
, privacy
);
276 //======================================================================================================================
279 dnssd_object_finalize(dnssd_any_t object
)
281 for (dnssd_kind_t kind
= object
.base
->kind
; kind
; kind
= kind
->superkind
) {
282 if (kind
->finalize
) {
283 kind
->finalize(object
);
289 //======================================================================================================================
290 #pragma mark - dnssd_getaddrinfo Public Methods
294 dnssd_getaddrinfo_create(void)
296 dnssd_getaddrinfo_t gai
= NULL
;
297 dnssd_getaddrinfo_t obj
= _dnssd_getaddrinfo_alloc();
298 require_quiet(obj
, exit
);
300 obj
->params
= xpc_dictionary_create(NULL
, NULL
, 0);
301 require_quiet(obj
->params
, exit
);
303 obj
->mutex_queue
= dispatch_queue_create("com.apple.dnssd.getaddrinfo.mutex", DISPATCH_QUEUE_SERIAL
);
304 require_quiet(obj
->mutex_queue
, exit
);
310 dnssd_release_null_safe(obj
);
314 //======================================================================================================================
317 dnssd_getaddrinfo_set_queue(dnssd_getaddrinfo_t me
, dispatch_queue_t queue
)
319 if (!me
->user_activated
) {
320 dispatch_retain(queue
);
321 dispatch_release_null_safe(me
->user_queue
);
322 me
->user_queue
= queue
;
323 } else if (!me
->user_queue
) {
324 me
->user_queue
= queue
;
325 dispatch_retain(me
->user_queue
);
326 _dnssd_client_activate_getaddrinfo_async(me
);
330 //======================================================================================================================
333 dnssd_getaddrinfo_set_flags(dnssd_getaddrinfo_t me
, DNSServiceFlags flags
)
335 if (!me
->user_activated
) {
336 dnssd_xpc_parameters_set_flags(me
->params
, flags
);
340 //======================================================================================================================
343 dnssd_getaddrinfo_set_hostname(dnssd_getaddrinfo_t me
, const char *hostname
)
345 if (!me
->user_activated
) {
346 dnssd_xpc_parameters_set_hostname(me
->params
, hostname
);
350 //======================================================================================================================
353 dnssd_getaddrinfo_set_interface_index(dnssd_getaddrinfo_t me
, uint32_t interface_index
)
355 if (!me
->user_activated
) {
356 dnssd_xpc_parameters_set_interface_index(me
->params
, interface_index
);
360 //======================================================================================================================
363 dnssd_getaddrinfo_set_protocols(dnssd_getaddrinfo_t me
, DNSServiceProtocol protocols
)
365 if (!me
->user_activated
) {
366 dnssd_xpc_parameters_set_protocols(me
->params
, protocols
);
370 //======================================================================================================================
373 dnssd_getaddrinfo_set_delegate_pid(dnssd_getaddrinfo_t me
, pid_t pid
)
375 if (!me
->user_activated
) {
376 dnssd_xpc_parameters_set_delegate_pid(me
->params
, pid
);
380 //======================================================================================================================
383 dnssd_getaddrinfo_set_delegate_uuid(dnssd_getaddrinfo_t me
, uuid_t uuid
)
385 if (!me
->user_activated
) {
386 dnssd_xpc_parameters_set_delegate_uuid(me
->params
, uuid
);
390 //======================================================================================================================
393 dnssd_getaddrinfo_set_result_handler(dnssd_getaddrinfo_t me
, dnssd_getaddrinfo_result_handler_t handler
)
395 dnssd_getaddrinfo_result_handler_t
const new_handler
= handler
? Block_copy(handler
) : NULL
;
396 if (me
->result_handler
) {
397 Block_release(me
->result_handler
);
399 me
->result_handler
= new_handler
;
402 //======================================================================================================================
405 dnssd_getaddrinfo_set_event_handler(dnssd_getaddrinfo_t me
, dnssd_event_handler_t handler
)
407 dnssd_event_handler_t
const new_handler
= handler
? Block_copy(handler
) : NULL
;
408 if (me
->event_handler
) {
409 Block_release(me
->event_handler
);
411 me
->event_handler
= new_handler
;
414 //======================================================================================================================
417 dnssd_getaddrinfo_set_need_authenticated_results(dnssd_getaddrinfo_t me
, bool need
)
419 if (!me
->user_activated
) {
420 dnssd_xpc_parameters_set_need_authentication_tags(me
->params
, need
);
424 //======================================================================================================================
427 dnssd_getaddrinfo_activate(dnssd_getaddrinfo_t me
)
429 if (!me
->user_activated
) {
430 if (me
->user_queue
) {
431 _dnssd_client_activate_getaddrinfo_async(me
);
433 me
->user_activated
= true;
437 //======================================================================================================================
440 _dnssd_client_invalidate_getaddrinfo(dnssd_getaddrinfo_t gai
);
443 _dnssd_getaddrinfo_invalidate(dnssd_getaddrinfo_t me
);
446 dnssd_getaddrinfo_invalidate(dnssd_getaddrinfo_t me
)
449 dispatch_async(_dnssd_client_queue(),
451 _dnssd_client_invalidate_getaddrinfo(me
);
457 _dnssd_client_invalidate_getaddrinfo(dnssd_getaddrinfo_t gai
)
459 require_quiet(gai
->state
!= dnssd_getaddrinfo_state_invalidated
, exit
);
461 _dnssd_client_deregister_getaddrinfo(gai
);
462 if ((gai
->state
== dnssd_getaddrinfo_state_starting
) || (gai
->state
== dnssd_getaddrinfo_state_started
)) {
463 xpc_object_t
const msg
= xpc_dictionary_create(NULL
, NULL
, 0);
465 dnssd_xpc_message_set_id(msg
, gai
->command_id
);
466 dnssd_xpc_message_set_command(msg
, DNSSD_COMMAND_STOP
);
467 xpc_connection_send_message_with_reply(_dnssd_client_connection(), msg
, _dnssd_client_queue(),
468 ^(xpc_object_t reply
)
475 _dnssd_getaddrinfo_invalidate(gai
);
476 gai
->state
= dnssd_getaddrinfo_state_invalidated
;
483 _dnssd_getaddrinfo_invalidate(dnssd_getaddrinfo_t me
)
485 dispatch_source_forget(&me
->event_source
);
486 _dnssd_getaddrinfo_remove_all_results(me
);
488 if (me
->user_queue
) {
490 dispatch_async(me
->user_queue
,
492 if (me
->event_handler
) {
493 me
->event_handler(dnssd_event_invalidated
, kDNSServiceErr_NoError
);
501 //======================================================================================================================
502 #pragma mark - dnssd_getaddrinfo Private Methods
506 _dnssd_getaddrinfo_copy_description(dnssd_getaddrinfo_t me
, const bool debug
, const bool privacy
)
508 const char *hostname
;
510 hostname
= xpc_string_get_string_ptr(me
->hostname
);
511 if (privacy
&& hostname
) {
512 hostname
= DNSSD_REDACTED_HOSTNAME_STR
;
519 char * buf_ptr
= NULL
;
524 char * dst
= buf_ptr
;
525 char * const end
= &buf_ptr
[buf_len
];
529 const size_t len
= (size_t)(end
- dst
);
530 n
= snprintf(dst
, len
, "dnssd_%s (%p): ", me
->base
.kind
->name
, (void *)me
);
531 require_quiet(n
>= 0, exit
);
534 dst
= (((size_t)n
) < len
) ? &dst
[n
] : end
;
539 n
= snprintf(dst
, (size_t)(end
- dst
), "hostname = %s", hostname
? hostname
: "<NO HOSTNAME>");
540 require_quiet(n
>= 0, exit
);
545 buf_ptr
= malloc(buf_len
);
546 require_quiet(buf_ptr
, exit
);
555 FreeNullSafe(buf_ptr
);
559 //======================================================================================================================
562 _dnssd_getaddrinfo_finalize(dnssd_getaddrinfo_t me
)
564 dispatch_forget(&me
->user_queue
);
565 dispatch_forget(&me
->mutex_queue
);
566 xpc_forget(&me
->params
);
567 xpc_forget(&me
->hostname
);
568 BlockForget(&me
->result_handler
);
569 BlockForget(&me
->event_handler
);
572 //======================================================================================================================
575 _dnssd_getaddrinfo_append_results(dnssd_getaddrinfo_t me
, dnssd_getaddrinfo_result_t result_list
)
577 dispatch_sync(me
->mutex_queue
,
579 dnssd_getaddrinfo_result_t
*ptr
= &me
->result_list
;
585 dispatch_source_merge_data(me
->event_source
, DNSSD_EVENT_HAVE_RESULTS
);
588 //======================================================================================================================
591 _dnssd_getaddrinfo_remove_all_results(dnssd_getaddrinfo_t me
)
593 dnssd_getaddrinfo_result_t result_list
= _dnssd_getaddrinfo_take_results(me
);
594 if (me
->event_source
) {
595 dispatch_source_merge_data(me
->event_source
, DNSSD_EVENT_REMOVE_ALL
);
598 dnssd_getaddrinfo_result_t result
;
599 while ((result
= result_list
) != NULL
) {
600 result_list
= result
->next
;
601 dnssd_release(result
);
605 //======================================================================================================================
607 static dnssd_getaddrinfo_result_t
608 _dnssd_getaddrinfo_take_results(dnssd_getaddrinfo_t me
)
610 __block dnssd_getaddrinfo_result_t list
;
611 dispatch_sync(me
->mutex_queue
,
613 list
= me
->result_list
;
614 me
->result_list
= NULL
;
619 //======================================================================================================================
622 _dnssd_getaddrinfo_post_error_event(dnssd_getaddrinfo_t me
, OSStatus error
)
624 dispatch_sync(me
->mutex_queue
,
628 dispatch_source_merge_data(me
->event_source
, DNSSD_EVENT_ERROR
);
632 //======================================================================================================================
633 #pragma mark - dnssd_getaddrinfo_result Public Methods
636 dnssd_getaddrinfo_result_type_t
637 dnssd_getaddrinfo_result_get_type(dnssd_getaddrinfo_result_t me
)
642 //======================================================================================================================
645 dnssd_getaddrinfo_result_get_actual_hostname(dnssd_getaddrinfo_result_t me
)
647 return xpc_string_get_string_ptr(me
->actual_hostname
);
650 //======================================================================================================================
652 const struct sockaddr
*
653 dnssd_getaddrinfo_result_get_address(dnssd_getaddrinfo_result_t me
)
658 //======================================================================================================================
661 dnssd_getaddrinfo_result_get_hostname(dnssd_getaddrinfo_result_t me
)
663 return xpc_string_get_string_ptr(me
->hostname
);
666 //======================================================================================================================
669 dnssd_getaddrinfo_result_get_interface_index(dnssd_getaddrinfo_result_t me
)
671 return me
->interface_index
;
674 //======================================================================================================================
677 dnssd_getaddrinfo_result_get_authentication_tag(dnssd_getaddrinfo_result_t me
, size_t *out_length
)
679 const void * auth_tag_ptr
;
683 auth_tag_ptr
= xpc_data_get_bytes_ptr(me
->auth_tag
);
684 auth_tag_len
= xpc_data_get_length(me
->auth_tag
);
690 *out_length
= auth_tag_len
;
696 //======================================================================================================================
697 #pragma mark - dnssd_getaddrinfo_result Private Methods
701 _dnssd_getaddrinfo_result_copy_description(dnssd_getaddrinfo_result_t me
, const bool debug
, const bool privacy
)
703 const char *hostname
;
705 hostname
= xpc_string_get_string_ptr(me
->hostname
);
706 if (privacy
&& hostname
) {
707 hostname
= DNSSD_REDACTED_HOSTNAME_STR
;
713 const char *actual_hostname
;
714 if (me
->actual_hostname
) {
715 actual_hostname
= xpc_string_get_string_ptr(me
->actual_hostname
);
716 if (privacy
&& actual_hostname
) {
717 actual_hostname
= DNSSD_REDACTED_ACTUAL_HOSTNAME_STR
;
720 actual_hostname
= NULL
;
722 char addr_buf
[INET6_ADDRSTRLEN
];
723 check_compile_time_code(sizeof(addr_buf
) >= INET_ADDRSTRLEN
);
724 check_compile_time_code(sizeof(addr_buf
) >= INET6_ADDRSTRLEN
);
727 if (me
->addr
.sa
.sa_family
== AF_INET
) {
729 addr
= DNSSD_REDACTED_IPv4_ADDRESS_STR
;
731 addr
= inet_ntop(AF_INET
, &me
->addr
.v4
.sin_addr
.s_addr
, addr_buf
, (socklen_t
)sizeof(addr_buf
));
733 } else if (me
->addr
.sa
.sa_family
== AF_INET6
) {
735 addr
= DNSSD_REDACTED_IPv6_ADDRESS_STR
;
737 addr
= inet_ntop(AF_INET6
, me
->addr
.v6
.sin6_addr
.s6_addr
, addr_buf
, (socklen_t
)sizeof(addr_buf
));
744 char * buf_ptr
= NULL
;
748 char * dst
= buf_ptr
;
749 char * const end
= &buf_ptr
[buf_len
];
754 const size_t len
= (size_t)(end
- dst
);
755 n
= snprintf(dst
, len
, "dnssd_%s (%p): ", me
->base
.kind
->name
, (void *)me
);
756 require_quiet(n
>= 0, exit
);
759 dst
= (((size_t)n
) < len
) ? &dst
[n
] : end
;
764 n
= snprintf(dst
, (size_t)(end
- dst
), "[%s] %s (%s) -> %s (interface index %lu)",
765 dnssd_getaddrinfo_result_type_to_string(me
->type
), hostname
? hostname
: "<NO HOSTNAME>",
766 actual_hostname
? actual_hostname
: "<NO ACTUAL HOSTNAME>", addr
? addr
: "<NO IP ADDRESS>",
767 (unsigned long)me
->interface_index
);
768 require_quiet(n
>= 0, exit
);
773 buf_ptr
= malloc(buf_len
);
774 require_quiet(buf_ptr
, exit
);
783 FreeNullSafe(buf_ptr
);
787 //======================================================================================================================
790 _dnssd_getaddrinfo_result_finalize(dnssd_getaddrinfo_result_t me
)
792 xpc_forget(&me
->hostname
);
793 xpc_forget(&me
->actual_hostname
);
794 xpc_forget(&me
->auth_tag
);
798 //======================================================================================================================
799 #pragma mark - dnssd Client
802 static dnssd_getaddrinfo_t g_gai_list
= NULL
;
804 static dispatch_queue_t
805 _dnssd_client_queue(void)
807 static dispatch_once_t once
= 0;
808 static dispatch_queue_t queue
= NULL
;
812 dispatch_queue_attr_t
const attr
= dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL
,
813 QOS_CLASS_UTILITY
, 0);
814 queue
= dispatch_queue_create("com.apple.dnssd.client", attr
);
819 //======================================================================================================================
822 _dnssd_client_handle_message(xpc_object_t msg
);
824 _dnssd_client_handle_interruption(void);
826 static xpc_connection_t
827 _dnssd_client_connection(void)
829 static dispatch_once_t once
= 0;
830 static xpc_connection_t connection
= NULL
;
834 connection
= xpc_connection_create_mach_service(DNSSD_MACH_SERVICE_NAME
, _dnssd_client_queue(),
835 XPC_CONNECTION_MACH_SERVICE_PRIVILEGED
);
836 xpc_connection_set_event_handler(connection
,
837 ^(xpc_object_t event
)
839 if (xpc_get_type(event
) == XPC_TYPE_DICTIONARY
) {
840 _dnssd_client_handle_message(event
);
841 } else if (event
== XPC_ERROR_CONNECTION_INTERRUPTED
) {
842 _dnssd_client_handle_interruption();
845 xpc_connection_activate(connection
);
851 _dnssd_client_handle_message(xpc_object_t msg
)
853 const uint64_t command_id
= dnssd_xpc_message_get_id(msg
, NULL
);
854 dnssd_getaddrinfo_t gai
;
855 for (gai
= g_gai_list
; gai
; gai
= gai
->next
) {
856 if (gai
->command_id
== command_id
) {
860 require_quiet(gai
, exit
);
862 const OSStatus error
= dnssd_xpc_message_get_error(msg
, NULL
);
864 xpc_object_t
const result_array
= dnssd_xpc_message_get_results(msg
);
865 require_quiet(result_array
, exit
);
867 dnssd_getaddrinfo_result_t result_list
= NULL
;
868 __block dnssd_getaddrinfo_result_t
* result_ptr
= &result_list
;
869 xpc_array_apply(result_array
,
870 ^bool(__unused
size_t index
, xpc_object_t result_dict
)
872 dnssd_getaddrinfo_result_t result
= _dnssd_getaddrinfo_result_create_from_dictionary(gai
->hostname
,
875 *result_ptr
= result
;
876 result_ptr
= &result
->next
;
880 require_quiet(result_list
, exit
);
882 _dnssd_getaddrinfo_append_results(gai
, result_list
);
885 _dnssd_client_fail_getaddrinfo(gai
, error
);
893 _dnssd_client_handle_interruption(void)
895 dnssd_getaddrinfo_t next_gai
;
896 for (dnssd_getaddrinfo_t gai
= g_gai_list
; gai
; gai
= next_gai
) {
897 next_gai
= gai
->next
;
898 gai
->state
= dnssd_getaddrinfo_state_starting
;
899 const OSStatus err
= _dnssd_client_send_getaddrinfo_command(gai
);
901 _dnssd_getaddrinfo_remove_all_results(gai
);
903 _dnssd_client_fail_getaddrinfo(gai
, err
);
908 //======================================================================================================================
911 _dnssd_client_get_new_id(void)
913 static uint64_t last_id
= 0;
917 //======================================================================================================================
920 _dnssd_client_activate_getaddrinfo(dnssd_getaddrinfo_t gai
);
923 _dnssd_getaddrinfo_activate(dnssd_getaddrinfo_t gai
);
926 _dnssd_client_activate_getaddrinfo_async(dnssd_getaddrinfo_t gai
)
929 dispatch_async(_dnssd_client_queue(),
931 _dnssd_client_activate_getaddrinfo(gai
);
937 _dnssd_client_activate_getaddrinfo(dnssd_getaddrinfo_t gai
)
940 require_action_quiet(gai
->state
== dnssd_getaddrinfo_state_nascent
, exit
, err
= kNoErr
);
942 err
= _dnssd_getaddrinfo_activate(gai
);
944 gai
->state
= dnssd_getaddrinfo_state_failed
;
948 gai
->command_id
= _dnssd_client_get_new_id();
949 gai
->state
= dnssd_getaddrinfo_state_starting
;
951 _dnssd_client_register_getaddrinfo(gai
);
953 err
= _dnssd_client_send_getaddrinfo_command(gai
);
955 _dnssd_client_fail_getaddrinfo(gai
, err
);
963 _dnssd_getaddrinfo_process_events(dnssd_getaddrinfo_t gai
, unsigned long events
);
966 _dnssd_getaddrinfo_activate(dnssd_getaddrinfo_t me
)
969 xpc_object_t
const hostname
= dnssd_xpc_parameters_get_hostname_object(me
->params
);
970 require_action_quiet(hostname
, exit
, err
= kParamErr
);
972 me
->hostname
= xpc_copy(hostname
);
973 require_action_quiet(me
->hostname
, exit
, err
= kNoResourcesErr
);
975 me
->event_source
= dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_OR
, 0, 0, me
->user_queue
);
976 require_action_quiet(me
->event_source
, exit
, err
= kNoResourcesErr
);
979 dispatch_source_t
const event_source
= me
->event_source
;
980 dispatch_source_set_event_handler(me
->event_source
,
982 _dnssd_getaddrinfo_process_events(me
, dispatch_source_get_data(event_source
));
984 dispatch_source_set_cancel_handler(me
->event_source
,
988 dispatch_activate(me
->event_source
);
994 dispatch_async(me
->user_queue
,
996 if (me
->event_handler
) {
997 me
->event_handler(dnssd_event_error
, _dnssd_osstatus_to_dns_service_error(err
));
1006 _dnssd_getaddrinfo_process_events(dnssd_getaddrinfo_t me
, unsigned long events
)
1008 if (events
& DNSSD_EVENT_REMOVE_ALL
) {
1009 if (me
->event_handler
) {
1010 me
->event_handler(dnssd_event_remove_all
, kDNSServiceErr_NoError
);
1014 if (events
& DNSSD_EVENT_HAVE_RESULTS
) {
1015 dnssd_getaddrinfo_result_t result
;
1016 dnssd_getaddrinfo_result_t result_array
[32];
1017 dnssd_getaddrinfo_result_t result_list
= _dnssd_getaddrinfo_take_results(me
);
1019 size_t result_count
= 0;
1020 while ((result
= result_list
) != NULL
) {
1021 result_list
= result
->next
;
1022 result
->next
= NULL
;
1023 result_array
[result_count
++] = result
;
1025 if ((result_count
== countof(result_array
)) || !result_list
) {
1026 if (me
->result_handler
) {
1027 me
->result_handler(result_array
, result_count
);
1029 for (size_t i
= 0; i
< result_count
; ++i
) {
1030 dnssd_release(result_array
[i
]);
1037 if (events
& DNSSD_EVENT_ERROR
) {
1038 __block OSStatus error
;
1039 dispatch_sync(me
->mutex_queue
,
1044 if (me
->event_handler
&& error
) {
1045 me
->event_handler(dnssd_event_error
, _dnssd_osstatus_to_dns_service_error(error
));
1050 //======================================================================================================================
1053 _dnssd_client_register_getaddrinfo(dnssd_getaddrinfo_t gai
)
1055 gai
->next
= g_gai_list
;
1060 //======================================================================================================================
1063 _dnssd_client_deregister_getaddrinfo(dnssd_getaddrinfo_t gai
)
1065 dnssd_getaddrinfo_t
*ptr
;
1066 for (ptr
= &g_gai_list
; *ptr
; ptr
= &(*ptr
)->next
)
1079 //======================================================================================================================
1082 _dnssd_client_handle_getaddrinfo_reply(dnssd_getaddrinfo_t gai
, xpc_object_t reply
);
1085 _dnssd_client_send_getaddrinfo_command(dnssd_getaddrinfo_t gai
)
1088 xpc_object_t
const msg
= xpc_dictionary_create(NULL
, NULL
, 0);
1089 require_action_quiet(msg
, exit
, err
= kNoResourcesErr
);
1091 dnssd_xpc_message_set_id(msg
, gai
->command_id
);
1092 dnssd_xpc_message_set_command(msg
, DNSSD_COMMAND_GETADDRINFO
);
1093 dnssd_xpc_message_set_parameters(msg
, gai
->params
);
1096 xpc_connection_send_message_with_reply(_dnssd_client_connection(), msg
, _dnssd_client_queue(),
1097 ^(xpc_object_t reply
)
1099 _dnssd_client_handle_getaddrinfo_reply(gai
, reply
);
1110 _dnssd_client_handle_getaddrinfo_reply(dnssd_getaddrinfo_t gai
, xpc_object_t reply
)
1112 require_quiet(gai
->state
== dnssd_getaddrinfo_state_starting
, exit
);
1114 if (xpc_get_type(reply
) == XPC_TYPE_DICTIONARY
) {
1115 const OSStatus error
= dnssd_xpc_message_get_error(reply
, NULL
);
1117 _dnssd_client_fail_getaddrinfo(gai
, error
);
1119 gai
->state
= dnssd_getaddrinfo_state_started
;
1121 } else if (reply
!= XPC_ERROR_CONNECTION_INTERRUPTED
) {
1123 if (reply
== XPC_ERROR_CONNECTION_INVALID
) {
1124 error
= kDNSServiceErr_ServiceNotRunning
;
1126 error
= kDNSServiceErr_Unknown
;
1128 _dnssd_client_fail_getaddrinfo(gai
, error
);
1135 //======================================================================================================================
1138 _dnssd_client_fail_getaddrinfo(dnssd_getaddrinfo_t gai
, OSStatus error
)
1140 _dnssd_client_deregister_getaddrinfo(gai
);
1141 gai
->state
= dnssd_getaddrinfo_state_failed
;
1142 _dnssd_getaddrinfo_post_error_event(gai
, error
);
1145 //======================================================================================================================
1146 // _dnssd_getaddrinfo_result_create_from_dictionary
1147 //======================================================================================================================
1150 _dnssd_extract_result_dict_values(xpc_object_t result
, xpc_object_t
*out_hostname
, DNSServiceErrorType
*out_error
,
1151 DNSServiceFlags
*out_flags
, uint32_t *out_interface_index
, uint16_t *out_type
, uint16_t *out_class
,
1152 xpc_object_t
*out_rdata
, xpc_object_t
*out_auth_tag
);
1154 static dnssd_getaddrinfo_result_t
1155 _dnssd_getaddrinfo_result_create(dnssd_getaddrinfo_result_type_t type
, xpc_object_t hostname
,
1156 xpc_object_t actual_hostname
, int addr_family
, const void *addr_data
, uint32_t interface_index
,
1157 xpc_object_t auth_tag
, OSStatus
*out_error
);
1159 static dnssd_getaddrinfo_result_t
1160 _dnssd_getaddrinfo_result_create_from_dictionary(xpc_object_t hostname
, xpc_object_t result_dict
, OSStatus
*out_error
)
1163 xpc_object_t actual_hostname
, rdata
, auth_tag
;
1164 DNSServiceErrorType error
;
1165 DNSServiceFlags flags
;
1166 uint32_t interface_index
;
1168 dnssd_getaddrinfo_result_t result
= NULL
;
1170 const bool success
= _dnssd_extract_result_dict_values(result_dict
, &actual_hostname
, &error
, &flags
,
1171 &interface_index
, &rtype
, NULL
, &rdata
, &auth_tag
);
1172 require_action_quiet(success
, exit
, err
= kMalformedErr
);
1174 if ((error
!= kDNSServiceErr_NoError
) &&
1175 (error
!= kDNSServiceErr_NoSuchRecord
)) {
1176 err
= kUnexpectedErr
;
1179 require_action_quiet((rtype
== kDNSServiceType_A
) || (rtype
== kDNSServiceType_AAAA
), exit
, err
= kTypeErr
);
1181 dnssd_getaddrinfo_result_type_t result_type
;
1182 if (error
== kDNSServiceErr_NoSuchRecord
) {
1183 result_type
= dnssd_getaddrinfo_result_type_no_address
;
1185 if (flags
& kDNSServiceFlagsAdd
) {
1186 if (flags
& kDNSServiceFlagsExpiredAnswer
) {
1187 result_type
= dnssd_getaddrinfo_result_type_expired
;
1189 result_type
= dnssd_getaddrinfo_result_type_add
;
1192 result_type
= dnssd_getaddrinfo_result_type_remove
;
1194 if (rtype
== kDNSServiceType_A
) {
1195 require_action_quiet(xpc_data_get_length(rdata
) == 4, exit
, err
= kMalformedErr
);
1197 require_action_quiet(xpc_data_get_length(rdata
) == 16, exit
, err
= kMalformedErr
);
1200 const int addr_family
= (rtype
== kDNSServiceType_A
) ? AF_INET
: AF_INET6
;
1201 result
= _dnssd_getaddrinfo_result_create(result_type
, hostname
, actual_hostname
, addr_family
,
1202 xpc_data_get_bytes_ptr(rdata
), interface_index
, auth_tag
, &err
);
1203 require_noerr_quiet(err
, exit
);
1207 dnssd_forget(&result
);
1216 _dnssd_extract_result_dict_values(xpc_object_t result
, xpc_object_t
*out_hostname
, DNSServiceErrorType
*out_error
,
1217 DNSServiceFlags
*out_flags
, uint32_t *out_interface_index
, uint16_t *out_type
, uint16_t *out_class
,
1218 xpc_object_t
*out_rdata
, xpc_object_t
*out_auth_tag
)
1220 bool result_is_valid
= false;
1221 xpc_object_t
const hostname
= dnssd_xpc_result_get_record_name_object(result
);
1222 require_quiet(hostname
, exit
);
1224 xpc_object_t
const rdata
= dnssd_xpc_result_get_record_data_object(result
);
1225 require_quiet(rdata
, exit
);
1228 *out_hostname
= hostname
;
1231 *out_error
= dnssd_xpc_result_get_error(result
, NULL
);
1234 *out_flags
= dnssd_xpc_result_get_flags(result
, NULL
);
1236 if (out_interface_index
) {
1237 *out_interface_index
= dnssd_xpc_result_get_interface_index(result
, NULL
);
1240 *out_type
= dnssd_xpc_result_get_record_type(result
, NULL
);
1243 *out_class
= dnssd_xpc_result_get_record_class(result
, NULL
);
1249 *out_auth_tag
= dnssd_xpc_result_get_authentication_tag_object(result
);
1251 result_is_valid
= true;
1254 return result_is_valid
;
1257 static dnssd_getaddrinfo_result_t
1258 _dnssd_getaddrinfo_result_create(dnssd_getaddrinfo_result_type_t type
, xpc_object_t hostname
,
1259 xpc_object_t actual_hostname
, int addr_family
, const void *addr_data
, uint32_t interface_index
,
1260 xpc_object_t auth_tag
, OSStatus
*out_error
)
1263 dnssd_getaddrinfo_result_t result
= NULL
;
1264 dnssd_getaddrinfo_result_t obj
= _dnssd_getaddrinfo_result_alloc();
1265 require_action_quiet(obj
, exit
, err
= kNoMemoryErr
);
1268 case dnssd_getaddrinfo_result_type_add
:
1269 case dnssd_getaddrinfo_result_type_remove
:
1270 case dnssd_getaddrinfo_result_type_no_address
:
1271 case dnssd_getaddrinfo_result_type_expired
:
1279 obj
->interface_index
= interface_index
;
1281 require_action_quiet(xpc_get_type(hostname
) == XPC_TYPE_STRING
, exit
, err
= kTypeErr
);
1283 obj
->hostname
= xpc_copy(hostname
);
1284 require_action_quiet(obj
->hostname
, exit
, err
= kNoResourcesErr
);
1286 require_action_quiet(xpc_get_type(actual_hostname
) == XPC_TYPE_STRING
, exit
, err
= kTypeErr
);
1288 obj
->actual_hostname
= xpc_copy(actual_hostname
);
1289 require_action_quiet(obj
->actual_hostname
, exit
, err
= kNoResourcesErr
);
1291 require_action_quiet((addr_family
== AF_INET
) || (addr_family
== AF_INET6
), exit
, err
= kTypeErr
);
1293 if (addr_family
== AF_INET
) {
1294 obj
->addr
.sa
.sa_family
= AF_INET
;
1295 obj
->addr
.v4
.sin_len
= sizeof(struct sockaddr_in
);
1296 if (obj
->type
!= dnssd_getaddrinfo_result_type_no_address
) {
1297 memcpy(&obj
->addr
.v4
.sin_addr
.s_addr
, addr_data
, 4);
1300 obj
->addr
.sa
.sa_family
= AF_INET6
;
1301 obj
->addr
.v6
.sin6_len
= sizeof(struct sockaddr_in6
);
1302 if (obj
->type
!= dnssd_getaddrinfo_result_type_no_address
) {
1303 memcpy(&obj
->addr
.v6
.sin6_addr
.s6_addr
, addr_data
, 16);
1308 require_action_quiet(xpc_get_type(auth_tag
) == XPC_TYPE_DATA
, exit
, err
= kTypeErr
);
1310 obj
->auth_tag
= xpc_copy(auth_tag
);
1311 require_action_quiet(obj
->auth_tag
, exit
, err
= kNoResourcesErr
);
1321 dnssd_release_null_safe(obj
);
1326 //======================================================================================================================
1327 #pragma mark - Misc. Helpers
1330 static DNSServiceErrorType
1331 _dnssd_osstatus_to_dns_service_error(OSStatus error
)
1335 case kNoResourcesErr
:
1336 error
= kDNSServiceErr_NoMemory
;
1340 error
= kDNSServiceErr_BadParam
;
1344 if ((error
>= kGenericErrorBase
) && (error
<= kGenericErrorEnd
)) {
1345 error
= kDNSServiceErr_Unknown
;