2 * Copyright (c) 2013-2017 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
26 * - IPC channel to IPMonitor
27 * - used to create interface rank assertions
31 * Modification History
33 * December 16, 2013 Dieter Siegmund (dieter@apple.com)
37 #include "IPMonitorControl.h"
38 #include "IPMonitorControlPrivate.h"
39 #include "symbol_scope.h"
40 #include <CoreFoundation/CFRuntime.h>
43 #include <xpc/private.h>
44 #include <SystemConfiguration/SCPrivate.h>
46 #ifdef TEST_IPMONITOR_CONTROL
48 #define my_log(__level, __format, ...) SCPrint(TRUE, stdout, CFSTR(__format "\n"), ## __VA_ARGS__)
50 #else /* TEST_IPMONITOR_CONTROL */
52 #define my_log(__level, __format, ...) SC_log(__level, __format, ## __VA_ARGS__)
54 #endif /* TEST_IPMONITOR_CONTROL */
57 ** IPMonitorControl CF object glue
60 struct IPMonitorControl
{
61 CFRuntimeBase cf_base
;
63 #ifdef VERBOSE_ACTIVITY_LOGGING
64 os_activity_t activity
;
65 #endif // VERBOSE_ACTIVITY_LOGGING
66 dispatch_queue_t queue
;
67 xpc_connection_t connection
;
68 CFMutableDictionaryRef assertions
; /* ifname<string> = rank<number> */
71 STATIC CFStringRef
__IPMonitorControlCopyDebugDesc(CFTypeRef cf
);
72 STATIC
void __IPMonitorControlDeallocate(CFTypeRef cf
);
74 STATIC CFTypeID __kIPMonitorControlTypeID
= _kCFRuntimeNotATypeID
;
76 STATIC
const CFRuntimeClass __IPMonitorControlClass
= {
78 "IPMonitorControl", /* className */
81 __IPMonitorControlDeallocate
, /* deallocate */
84 NULL
, /* copyFormattingDesc */
85 __IPMonitorControlCopyDebugDesc
/* copyDebugDesc */
89 __IPMonitorControlCopyDebugDesc(CFTypeRef cf
)
91 CFAllocatorRef allocator
= CFGetAllocator(cf
);
92 IPMonitorControlRef control
= (IPMonitorControlRef
)cf
;
94 return (CFStringCreateWithFormat(allocator
, NULL
,
95 CFSTR("<IPMonitorControl %p>"),
100 __IPMonitorControlDeallocate(CFTypeRef cf
)
102 IPMonitorControlRef control
= (IPMonitorControlRef
)cf
;
104 if (control
->connection
!= NULL
) {
105 xpc_release(control
->connection
);
107 #ifdef VERBOSE_ACTIVITY_LOGGING
108 if (control
->activity
!= NULL
) {
109 os_release(control
->activity
);
111 #endif // VERBOSE_ACTIVITY_LOGGING
112 if (control
->queue
!= NULL
) {
113 xpc_release(control
->queue
);
119 ** IPMonitorControl support functions
122 __IPMonitorControlRegisterClass(void)
124 STATIC dispatch_once_t once
;
126 dispatch_once(&once
, ^{
127 __kIPMonitorControlTypeID
128 = _CFRuntimeRegisterClass(&__IPMonitorControlClass
);
133 STATIC IPMonitorControlRef
134 __IPMonitorControlAllocate(CFAllocatorRef allocator
)
136 IPMonitorControlRef control
;
139 __IPMonitorControlRegisterClass();
140 size
= sizeof(*control
) - sizeof(CFRuntimeBase
);
141 control
= (IPMonitorControlRef
)
142 _CFRuntimeCreateInstance(allocator
,
143 __kIPMonitorControlTypeID
, size
, NULL
);
148 IPMonitorControlHandleResponse(xpc_object_t event
, Boolean async
,
151 Boolean retry
= FALSE
;
152 Boolean success
= FALSE
;
155 type
= xpc_get_type(event
);
156 if (type
== XPC_TYPE_DICTIONARY
) {
158 /* we don't expect async responses messages */
159 my_log(LOG_NOTICE
, "unexpected message");
164 error
= xpc_dictionary_get_int64(event
,
165 kIPMonitorControlResponseKeyError
);
168 #ifdef TEST_IPMONITOR_CONTROL
169 my_log(LOG_NOTICE
, "failure code %lld", error
);
170 #endif /* TEST_IPMONITOR_CONTROL */
177 else if (type
== XPC_TYPE_ERROR
) {
178 if (event
== XPC_ERROR_CONNECTION_INTERRUPTED
) {
179 #ifdef TEST_IPMONITOR_CONTROL
180 my_log(LOG_NOTICE
, "can retry");
181 #endif /* TEST_IPMONITOR_CONTROL */
187 desc
= xpc_dictionary_get_string(event
, XPC_ERROR_KEY_DESCRIPTION
);
188 my_log(LOG_NOTICE
, "%s", desc
);
192 my_log(LOG_NOTICE
, "unknown event type : %p", type
);
194 if (retry_p
!= NULL
) {
202 IPMonitorControlSetInterfaceRank(IPMonitorControlRef control
,
203 CFStringRef ifname_cf
,
204 SCNetworkServicePrimaryRank rank
)
206 if (control
->assertions
== NULL
) {
207 if (rank
== kSCNetworkServicePrimaryRankDefault
) {
208 /* no assertions, no need to store rank */
212 = CFDictionaryCreateMutable(NULL
, 0,
213 &kCFTypeDictionaryKeyCallBacks
,
214 &kCFTypeDictionaryValueCallBacks
);
216 if (rank
== kSCNetworkServicePrimaryRankDefault
) {
217 CFDictionaryRemoveValue(control
->assertions
, ifname_cf
);
218 if (CFDictionaryGetCount(control
->assertions
) == 0) {
219 CFRelease(control
->assertions
);
220 control
->assertions
= NULL
;
226 rank_cf
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &rank
);
227 CFDictionarySetValue(control
->assertions
, ifname_cf
, rank_cf
);
234 ApplyInterfaceRank(const void * key
, const void * value
, void * context
)
236 xpc_connection_t connection
= (xpc_connection_t
)context
;
237 char ifname
[IF_NAMESIZE
];
238 SCNetworkServicePrimaryRank rank
;
239 xpc_object_t request
;
241 if (!CFStringGetCString(key
, ifname
, sizeof(ifname
),
242 kCFStringEncodingUTF8
)) {
245 if (!CFNumberGetValue(value
, kCFNumberSInt32Type
, &rank
)) {
248 request
= xpc_dictionary_create(NULL
, NULL
, 0);
249 xpc_dictionary_set_uint64(request
,
250 kIPMonitorControlRequestKeyType
,
251 kIPMonitorControlRequestTypeSetInterfaceRank
);
252 xpc_dictionary_set_string(request
,
253 kIPMonitorControlRequestKeyInterfaceName
,
255 xpc_dictionary_set_uint64(request
,
256 kIPMonitorControlRequestKeyPrimaryRank
,
258 xpc_connection_send_message(connection
, request
);
259 xpc_release(request
);
265 ** IPMonitorControl SPI
267 PRIVATE_EXTERN IPMonitorControlRef
268 IPMonitorControlCreate(void)
270 xpc_connection_t connection
;
271 IPMonitorControlRef control
;
272 uint64_t flags
= XPC_CONNECTION_MACH_SERVICE_PRIVILEGED
;
273 xpc_handler_t handler
;
274 dispatch_queue_t queue
;
276 control
= __IPMonitorControlAllocate(NULL
);
277 queue
= dispatch_queue_create("IPMonitorControl", NULL
);
279 = xpc_connection_create_mach_service(kIPMonitorControlServerName
,
281 handler
= ^(xpc_object_t event
) {
282 os_activity_t activity
;
285 activity
= os_activity_create("processing IPMonitor [rank] reply",
287 OS_ACTIVITY_FLAG_DEFAULT
);
288 os_activity_scope(activity
);
290 (void)IPMonitorControlHandleResponse(event
, TRUE
, &retry
);
291 if (retry
&& control
->assertions
!= NULL
) {
292 CFDictionaryApplyFunction(control
->assertions
,
294 control
->connection
);
297 os_release(activity
);
299 xpc_connection_set_event_handler(connection
, handler
);
300 #ifdef VERBOSE_ACTIVITY_LOGGING
301 control
->activity
= os_activity_create("accessing IPMonitor [rank] controls",
303 OS_ACTIVITY_FLAG_DEFAULT
);
304 #endif // VERBOSE_ACTIVITY_LOGGING
305 control
->connection
= connection
;
306 control
->queue
= queue
;
307 xpc_connection_resume(connection
);
311 PRIVATE_EXTERN Boolean
312 IPMonitorControlSetInterfacePrimaryRank(IPMonitorControlRef control
,
313 CFStringRef ifname_cf
,
314 SCNetworkServicePrimaryRank rank
)
316 char ifname
[IF_NAMESIZE
];
317 xpc_object_t request
;
318 Boolean success
= FALSE
;
320 if (!CFStringGetCString(ifname_cf
, ifname
, sizeof(ifname
),
321 kCFStringEncodingUTF8
)) {
325 #ifdef VERBOSE_ACTIVITY_LOGGING
326 os_activity_scope(control
->activity
);
327 #endif // VERBOSE_ACTIVITY_LOGGING
329 request
= xpc_dictionary_create(NULL
, NULL
, 0);
330 xpc_dictionary_set_uint64(request
,
331 kIPMonitorControlRequestKeyType
,
332 kIPMonitorControlRequestTypeSetInterfaceRank
);
333 xpc_dictionary_set_string(request
,
334 kIPMonitorControlRequestKeyInterfaceName
,
336 xpc_dictionary_set_uint64(request
,
337 kIPMonitorControlRequestKeyPrimaryRank
,
341 Boolean retry_on_error
= FALSE
;
343 reply
= xpc_connection_send_message_with_reply_sync(control
->connection
,
346 my_log(LOG_NOTICE
, "failed to send message");
349 success
= IPMonitorControlHandleResponse(reply
, FALSE
,
355 if (retry_on_error
) {
358 my_log(LOG_NOTICE
, "fatal error");
361 xpc_release(request
);
366 dispatch_async(control
->queue
,
368 IPMonitorControlSetInterfaceRank(control
,
371 CFRelease(ifname_cf
);
378 SCNetworkServicePrimaryRank
379 IPMonitorControlGetInterfacePrimaryRank(IPMonitorControlRef control
,
380 CFStringRef ifname_cf
)
382 char ifname
[IF_NAMESIZE
];
383 SCNetworkServicePrimaryRank rank
;
384 xpc_object_t request
;
386 rank
= kSCNetworkServicePrimaryRankDefault
;
387 if (!CFStringGetCString(ifname_cf
, ifname
, sizeof(ifname
),
388 kCFStringEncodingUTF8
)) {
392 #ifdef VERBOSE_ACTIVITY_LOGGING
393 os_activity_scope(control
->activity
);
394 #endif // VERBOSE_ACTIVITY_LOGGING
396 request
= xpc_dictionary_create(NULL
, NULL
, 0);
397 xpc_dictionary_set_uint64(request
,
398 kIPMonitorControlRequestKeyType
,
399 kIPMonitorControlRequestTypeGetInterfaceRank
);
400 xpc_dictionary_set_string(request
,
401 kIPMonitorControlRequestKeyInterfaceName
,
405 Boolean retry_on_error
= FALSE
;
408 reply
= xpc_connection_send_message_with_reply_sync(control
->connection
,
411 my_log(LOG_NOTICE
, "failed to send message");
414 success
= IPMonitorControlHandleResponse(reply
, FALSE
, &retry_on_error
);
416 rank
= (SCNetworkServicePrimaryRank
)
417 xpc_dictionary_get_uint64(reply
,
418 kIPMonitorControlResponseKeyPrimaryRank
);
424 if (retry_on_error
) {
429 xpc_release(request
);