1 /* advertising_proxy_services.h
3 * Copyright (c) 2020 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 * This file contains the implementation of the SRP Advertising Proxy management
18 * API on MacOS, which is private API used to control and manage the advertising
25 #include "xpc_clients.h"
26 #include "advertising_proxy_services.h"
29 #if defined(TARGET_OS_TV)
31 //*************************************************************************************************************
34 typedef struct _advertising_proxy_conn_ref_t
36 int ref_count
; // This structure is refcounted
37 xpc_connection_t connection
; // xpc_connection between client and daemon
38 advertising_proxy_reply app_callback
; // Callback function ptr for Client
39 dispatch_queue_t client_queue
; // Queue specified by client for scheduling its Callback
40 const char *command_name
; // The advertising proxy command we've been given
44 advertising_proxy_ref_finalize(adv_conn_ref_t
*conn_ref
)
49 void advertising_proxy_ref_dealloc(adv_conn_ref_t
*conn_ref
)
53 os_log(OS_LOG_DEFAULT
, "dns_services: advertising_proxy_ref_dealloc called with NULL advertising_proxy_conn_ref");
56 conn_ref
->app_callback
= NULL
;
57 if (conn_ref
->connection
!= NULL
) {
58 xpc_connection_cancel(conn_ref
->connection
);
61 // This is releasing the caller's reference. We may still have an internal reference.
62 RELEASE_HERE(conn_ref
, advertising_proxy_ref_finalize
);
63 os_log(OS_LOG_DEFAULT
, "dns_services: advertising_proxy_ref_dealloc successfully released conn_ref");
67 adv_connection_finalize(void *v_conn_ref
)
69 adv_conn_ref_t
*conn_ref
= v_conn_ref
;
70 os_log(OS_LOG_DEFAULT
, "adv_connection_finalize: releasing conn_ref at %d", conn_ref
->ref_count
);
71 RELEASE_HERE(conn_ref
, advertising_proxy_ref_finalize
);
74 // Called for errors. The cancel argument is set to true if we need the callback to cancel the connection, as will be
75 // true for errors other than XPC_ERROR_CONNECTION_INVALID. If the callback doesn't call advertising_proxy_ref_dealloc,
76 // which will cancel the connection, then adv_connection_call_callback cancels it.
78 adv_connection_call_callback(adv_conn_ref_t
*conn_ref
, xpc_object_t
*event
, int status
, bool cancel
)
80 int ref_count
= conn_ref
->ref_count
;
81 conn_ref
->app_callback(conn_ref
, event
, status
);
82 if (conn_ref
->ref_count
> 1 && conn_ref
->ref_count
== ref_count
) {
83 #ifndef __clang_analyzer__
84 RELEASE_HERE(conn_ref
, advertising_proxy_ref_finalize
);
87 xpc_connection_cancel(conn_ref
->connection
);
91 // We can never call the callback again after reporting an error.
92 conn_ref
->app_callback
= NULL
;
96 adv_event_handler(xpc_object_t event
, adv_conn_ref_t
*conn_ref
)
98 if (event
== XPC_ERROR_CONNECTION_INVALID
) {
99 os_log(OS_LOG_DEFAULT
, "adv_event_handler (%s): cleanup %p %p", conn_ref
->command_name
, conn_ref
, conn_ref
->connection
);
100 if (conn_ref
->app_callback
!= NULL
) {
101 adv_connection_call_callback(conn_ref
, event
, kDNSSDAdvertisingProxyStatus_Disconnected
, false);
103 os_log(OS_LOG_DEFAULT
, "No callback");
105 if (conn_ref
->connection
!= NULL
) {
106 xpc_release(conn_ref
->connection
);
107 conn_ref
->connection
= NULL
;
109 ERROR("adv_event_handler(%s): cleanup: conn_ref->connection is NULL when it shouldn't be!",
110 conn_ref
->command_name
);
112 } else if (xpc_get_type(event
) == XPC_TYPE_DICTIONARY
) {
113 if (conn_ref
->app_callback
!= NULL
) {
114 conn_ref
->app_callback(conn_ref
, event
, kDNSSDAdvertisingProxyStatus_NoError
);
116 os_log(OS_LOG_DEFAULT
, "adv_event_handler (%s): no callback", conn_ref
->command_name
);
119 os_log(OS_LOG_DEFAULT
, "adv_event_handler: Unexpected Connection Error [%s]",
120 xpc_dictionary_get_string(event
, XPC_ERROR_KEY_DESCRIPTION
));
121 if (conn_ref
->app_callback
) {
122 adv_connection_call_callback(conn_ref
, event
, kDNSSDAdvertisingProxyStatus_DaemonNotRunning
, true);
124 os_log(OS_LOG_DEFAULT
, "adv_event_handler: no callback");
125 xpc_connection_cancel(conn_ref
->connection
);
130 // Creates a new advertising_proxy_ Connection Reference(advertising_proxy_conn_ref)
131 static advertising_proxy_error_type
132 adv_init_connection(adv_conn_ref_t
**ref
, const char *servname
, xpc_object_t dict
,
133 const char *command_name
, advertising_proxy_reply app_callback
, dispatch_queue_t client_queue
,
134 const char *file
, int line
)
136 // Use an adv_conn_ref_t *on the stack to be captured in the blocks below, rather than
137 // capturing the advertising_proxy_conn_ref* owned by the client
138 adv_conn_ref_t
*conn_ref
= calloc(1, sizeof(adv_conn_ref_t
));
139 if (conn_ref
== NULL
) {
140 os_log(OS_LOG_DEFAULT
, "dns_services: init_connection() No memory to allocate!");
141 return kDNSSDAdvertisingProxyStatus_NoMemory
;
144 // Initialize the advertising_proxy_conn_ref
145 dispatch_retain(client_queue
);
146 conn_ref
->command_name
= command_name
;
147 conn_ref
->client_queue
= client_queue
;
148 conn_ref
->app_callback
= app_callback
;
149 conn_ref
->connection
= xpc_connection_create_mach_service(servname
, conn_ref
->client_queue
,
150 XPC_CONNECTION_MACH_SERVICE_PRIVILEGED
);
152 if (conn_ref
->connection
== NULL
)
154 os_log(OS_LOG_DEFAULT
, "dns_services: init_connection() conn_ref/lib_q is NULL");
155 if (conn_ref
!= NULL
) {
158 return kDNSSDAdvertisingProxyStatus_NoMemory
;
161 RETAIN_HERE(conn_ref
); // For the event handler.
162 xpc_connection_set_event_handler(conn_ref
->connection
, ^(xpc_object_t event
) { adv_event_handler(event
, conn_ref
); });
163 xpc_connection_set_finalizer_f(conn_ref
->connection
, adv_connection_finalize
);
164 xpc_connection_set_context(conn_ref
->connection
, conn_ref
);
165 xpc_connection_resume(conn_ref
->connection
);
167 xpc_connection_send_message_with_reply(conn_ref
->connection
, dict
, conn_ref
->client_queue
,
168 ^(xpc_object_t event
) { adv_event_handler(event
, conn_ref
); });
175 return kDNSSDAdvertisingProxyStatus_NoError
;
178 #define adv_send_command(ref, client_queue, command_name, dict, command, app_callback) \
179 adv_send_command_(ref, client_queue, command_name, dict, command, app_callback, __FILE__, __LINE__)
180 static advertising_proxy_error_type
181 adv_send_command_(adv_conn_ref_t
**ref
, dispatch_queue_t client_queue
, const char *command_name
,
182 xpc_object_t dict
, const char *command
, advertising_proxy_reply app_callback
, const char *file
, int line
)
184 advertising_proxy_error_type errx
= kDNSSDAdvertisingProxyStatus_NoError
;
187 os_log(OS_LOG_DEFAULT
, "adv_send_command(%s): no memory for command dictionary.", command_name
);
188 return kDNSSDAdvertisingProxyStatus_NoMemory
;
192 if (app_callback
== NULL
|| client_queue
== NULL
)
194 os_log(OS_LOG_DEFAULT
, "%s: NULL cti_connection_t OR Callback OR Client_Queue parameter",
196 return kDNSSDAdvertisingProxyStatus_BadParam
;
199 xpc_dictionary_set_string(dict
, kDNSAdvertisingProxyCommand
, command
);
201 errx
= adv_init_connection(ref
, kDNSAdvertisingProxyService
, dict
, command_name
, app_callback
, client_queue
, file
, line
);
202 if (errx
) // On error init_connection() leaves *conn_ref set to NULL
204 os_log(OS_LOG_DEFAULT
,
205 "%s: Since init_connection() returned %d error returning w/o sending msg",
214 advertising_proxy_error_type
215 advertising_proxy_enable(adv_conn_ref_t
**conn_ref
, dispatch_queue_t client_queue
, advertising_proxy_reply callback
)
217 advertising_proxy_error_type errx
;
218 xpc_object_t dict
= xpc_dictionary_create(NULL
, NULL
, 0);
220 errx
= adv_send_command(conn_ref
, client_queue
, "advertising_proxy_enable",
221 dict
, kDNSAdvertisingProxyEnable
, callback
);
226 advertising_proxy_error_type
227 advertising_proxy_flush_entries(adv_conn_ref_t
**conn_ref
,
228 dispatch_queue_t client_queue
, advertising_proxy_reply callback
)
230 advertising_proxy_error_type errx
;
231 xpc_object_t dict
= xpc_dictionary_create(NULL
, NULL
, 0);
233 errx
= adv_send_command(conn_ref
, client_queue
, "advertising_proxy_flush_entries",
234 dict
, kDNSAdvertisingProxyFlushEntries
, callback
);
239 advertising_proxy_error_type
240 advertising_proxy_get_service_list(adv_conn_ref_t
**conn_ref
,
241 dispatch_queue_t client_queue
, advertising_proxy_reply callback
)
243 advertising_proxy_error_type errx
;
244 xpc_object_t dict
= xpc_dictionary_create(NULL
, NULL
, 0);
246 errx
= adv_send_command(conn_ref
, client_queue
, "advertising_proxy_get_service_list",
247 dict
, kDNSAdvertisingProxyListServices
, callback
);
252 advertising_proxy_error_type
253 advertising_proxy_block_service(adv_conn_ref_t
**conn_ref
,
254 dispatch_queue_t client_queue
, advertising_proxy_reply callback
)
256 advertising_proxy_error_type errx
;
257 xpc_object_t dict
= xpc_dictionary_create(NULL
, NULL
, 0);
259 errx
= adv_send_command(conn_ref
, client_queue
, "advertising_proxy_block_service",
260 dict
, kDNSAdvertisingProxyBlockService
, callback
);
265 advertising_proxy_error_type
266 advertising_proxy_unblock_service(adv_conn_ref_t
**conn_ref
,
267 dispatch_queue_t client_queue
, advertising_proxy_reply callback
)
269 advertising_proxy_error_type errx
;
270 xpc_object_t dict
= xpc_dictionary_create(NULL
, NULL
, 0);
272 errx
= adv_send_command(conn_ref
, client_queue
, "advertising_proxy_unblock_service",
273 dict
, kDNSAdvertisingProxyUnblockService
, callback
);
278 advertising_proxy_error_type
279 advertising_proxy_regenerate_ula(adv_conn_ref_t
**conn_ref
,
280 dispatch_queue_t client_queue
, advertising_proxy_reply callback
)
282 advertising_proxy_error_type errx
;
283 xpc_object_t dict
= xpc_dictionary_create(NULL
, NULL
, 0);
285 errx
= adv_send_command(conn_ref
, client_queue
, "advertising_proxy_regenerate_ula",
286 dict
, kDNSAdvertisingProxyRegenerateULA
, callback
);
290 #endif // defined(TARGET_OS_TV)
295 // c-file-style: "bsd"
298 // indent-tabs-mode: nil