2 * Copyright (c) 2013-2016 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 os_activity_t activity
;
64 dispatch_queue_t queue
;
65 xpc_connection_t connection
;
66 CFMutableDictionaryRef assertions
; /* ifname<string> = rank<number> */
69 STATIC CFStringRef
__IPMonitorControlCopyDebugDesc(CFTypeRef cf
);
70 STATIC
void __IPMonitorControlDeallocate(CFTypeRef cf
);
72 STATIC CFTypeID __kIPMonitorControlTypeID
= _kCFRuntimeNotATypeID
;
74 STATIC
const CFRuntimeClass __IPMonitorControlClass
= {
76 "IPMonitorControl", /* className */
79 __IPMonitorControlDeallocate
, /* deallocate */
82 NULL
, /* copyFormattingDesc */
83 __IPMonitorControlCopyDebugDesc
/* copyDebugDesc */
87 __IPMonitorControlCopyDebugDesc(CFTypeRef cf
)
89 CFAllocatorRef allocator
= CFGetAllocator(cf
);
90 IPMonitorControlRef control
= (IPMonitorControlRef
)cf
;
92 return (CFStringCreateWithFormat(allocator
, NULL
,
93 CFSTR("<IPMonitorControl %p>"),
98 __IPMonitorControlDeallocate(CFTypeRef cf
)
100 IPMonitorControlRef control
= (IPMonitorControlRef
)cf
;
102 if (control
->connection
!= NULL
) {
103 xpc_release(control
->connection
);
105 if (control
->activity
!= NULL
) {
106 os_release(control
->activity
);
108 if (control
->queue
!= NULL
) {
109 xpc_release(control
->queue
);
115 ** IPMonitorControl support functions
118 __IPMonitorControlRegisterClass(void)
120 STATIC dispatch_once_t once
;
122 dispatch_once(&once
, ^{
123 __kIPMonitorControlTypeID
124 = _CFRuntimeRegisterClass(&__IPMonitorControlClass
);
129 STATIC IPMonitorControlRef
130 __IPMonitorControlAllocate(CFAllocatorRef allocator
)
132 IPMonitorControlRef control
;
135 __IPMonitorControlRegisterClass();
136 size
= sizeof(*control
) - sizeof(CFRuntimeBase
);
137 control
= (IPMonitorControlRef
)
138 _CFRuntimeCreateInstance(allocator
,
139 __kIPMonitorControlTypeID
, size
, NULL
);
144 IPMonitorControlHandleResponse(xpc_object_t event
, Boolean async
,
147 Boolean retry
= FALSE
;
148 Boolean success
= FALSE
;
151 type
= xpc_get_type(event
);
152 if (type
== XPC_TYPE_DICTIONARY
) {
154 /* we don't expect async responses messages */
155 my_log(LOG_NOTICE
, "unexpected message");
160 error
= xpc_dictionary_get_int64(event
,
161 kIPMonitorControlResponseKeyError
);
164 #ifdef TEST_IPMONITOR_CONTROL
165 my_log(LOG_NOTICE
, "failure code %lld", error
);
166 #endif /* TEST_IPMONITOR_CONTROL */
173 else if (type
== XPC_TYPE_ERROR
) {
174 if (event
== XPC_ERROR_CONNECTION_INTERRUPTED
) {
175 #ifdef TEST_IPMONITOR_CONTROL
176 my_log(LOG_NOTICE
, "can retry");
177 #endif /* TEST_IPMONITOR_CONTROL */
183 desc
= xpc_dictionary_get_string(event
, XPC_ERROR_KEY_DESCRIPTION
);
184 my_log(LOG_NOTICE
, "%s", desc
);
188 my_log(LOG_NOTICE
, "unknown event type : %p", type
);
190 if (retry_p
!= NULL
) {
198 IPMonitorControlSetInterfaceRank(IPMonitorControlRef control
,
199 CFStringRef ifname_cf
,
200 SCNetworkServicePrimaryRank rank
)
202 if (control
->assertions
== NULL
) {
203 if (rank
== kSCNetworkServicePrimaryRankDefault
) {
204 /* no assertions, no need to store rank */
208 = CFDictionaryCreateMutable(NULL
, 0,
209 &kCFTypeDictionaryKeyCallBacks
,
210 &kCFTypeDictionaryValueCallBacks
);
212 if (rank
== kSCNetworkServicePrimaryRankDefault
) {
213 CFDictionaryRemoveValue(control
->assertions
, ifname_cf
);
214 if (CFDictionaryGetCount(control
->assertions
) == 0) {
215 CFRelease(control
->assertions
);
216 control
->assertions
= NULL
;
222 rank_cf
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &rank
);
223 CFDictionarySetValue(control
->assertions
, ifname_cf
, rank_cf
);
230 ApplyInterfaceRank(const void * key
, const void * value
, void * context
)
232 xpc_connection_t connection
= (xpc_connection_t
)context
;
233 char ifname
[IF_NAMESIZE
];
234 SCNetworkServicePrimaryRank rank
;
235 xpc_object_t request
;
237 if (!CFStringGetCString(key
, ifname
, sizeof(ifname
),
238 kCFStringEncodingUTF8
)) {
241 if (!CFNumberGetValue(value
, kCFNumberSInt32Type
, &rank
)) {
244 request
= xpc_dictionary_create(NULL
, NULL
, 0);
245 xpc_dictionary_set_uint64(request
,
246 kIPMonitorControlRequestKeyType
,
247 kIPMonitorControlRequestTypeSetInterfaceRank
);
248 xpc_dictionary_set_string(request
,
249 kIPMonitorControlRequestKeyInterfaceName
,
251 xpc_dictionary_set_uint64(request
,
252 kIPMonitorControlRequestKeyPrimaryRank
,
254 xpc_connection_send_message(connection
, request
);
255 xpc_release(request
);
261 ** IPMonitorControl SPI
263 PRIVATE_EXTERN IPMonitorControlRef
264 IPMonitorControlCreate(void)
266 xpc_connection_t connection
;
267 IPMonitorControlRef control
;
268 uint64_t flags
= XPC_CONNECTION_MACH_SERVICE_PRIVILEGED
;
269 xpc_handler_t handler
;
270 dispatch_queue_t queue
;
272 control
= __IPMonitorControlAllocate(NULL
);
273 queue
= dispatch_queue_create("IPMonitorControl", NULL
);
275 = xpc_connection_create_mach_service(kIPMonitorControlServerName
,
277 handler
= ^(xpc_object_t event
) {
278 os_activity_t activity
;
281 activity
= os_activity_create("processing IPMonitor [rank] reply",
283 OS_ACTIVITY_FLAG_DEFAULT
);
284 os_activity_scope(activity
);
286 (void)IPMonitorControlHandleResponse(event
, TRUE
, &retry
);
287 if (retry
&& control
->assertions
!= NULL
) {
288 CFDictionaryApplyFunction(control
->assertions
,
290 control
->connection
);
293 os_release(activity
);
295 xpc_connection_set_event_handler(connection
, handler
);
296 control
->activity
= os_activity_create("accessing IPMonitor [rank] controls",
298 OS_ACTIVITY_FLAG_DEFAULT
);
299 control
->connection
= connection
;
300 control
->queue
= queue
;
301 xpc_connection_resume(connection
);
305 PRIVATE_EXTERN Boolean
306 IPMonitorControlSetInterfacePrimaryRank(IPMonitorControlRef control
,
307 CFStringRef ifname_cf
,
308 SCNetworkServicePrimaryRank rank
)
310 char ifname
[IF_NAMESIZE
];
311 xpc_object_t request
;
312 Boolean success
= FALSE
;
314 if (!CFStringGetCString(ifname_cf
, ifname
, sizeof(ifname
),
315 kCFStringEncodingUTF8
)) {
319 os_activity_scope(control
->activity
);
321 request
= xpc_dictionary_create(NULL
, NULL
, 0);
322 xpc_dictionary_set_uint64(request
,
323 kIPMonitorControlRequestKeyType
,
324 kIPMonitorControlRequestTypeSetInterfaceRank
);
325 xpc_dictionary_set_string(request
,
326 kIPMonitorControlRequestKeyInterfaceName
,
328 xpc_dictionary_set_uint64(request
,
329 kIPMonitorControlRequestKeyPrimaryRank
,
333 Boolean retry_on_error
= FALSE
;
335 reply
= xpc_connection_send_message_with_reply_sync(control
->connection
,
338 my_log(LOG_NOTICE
, "failed to send message");
341 success
= IPMonitorControlHandleResponse(reply
, FALSE
,
347 if (retry_on_error
) {
350 my_log(LOG_NOTICE
, "fatal error");
353 xpc_release(request
);
358 dispatch_async(control
->queue
,
360 IPMonitorControlSetInterfaceRank(control
,
363 CFRelease(ifname_cf
);
370 SCNetworkServicePrimaryRank
371 IPMonitorControlGetInterfacePrimaryRank(IPMonitorControlRef control
,
372 CFStringRef ifname_cf
)
374 char ifname
[IF_NAMESIZE
];
375 SCNetworkServicePrimaryRank rank
;
376 xpc_object_t request
;
378 rank
= kSCNetworkServicePrimaryRankDefault
;
379 if (!CFStringGetCString(ifname_cf
, ifname
, sizeof(ifname
),
380 kCFStringEncodingUTF8
)) {
384 os_activity_scope(control
->activity
);
386 request
= xpc_dictionary_create(NULL
, NULL
, 0);
387 xpc_dictionary_set_uint64(request
,
388 kIPMonitorControlRequestKeyType
,
389 kIPMonitorControlRequestTypeGetInterfaceRank
);
390 xpc_dictionary_set_string(request
,
391 kIPMonitorControlRequestKeyInterfaceName
,
395 Boolean retry_on_error
= FALSE
;
398 reply
= xpc_connection_send_message_with_reply_sync(control
->connection
,
401 my_log(LOG_NOTICE
, "failed to send message");
404 success
= IPMonitorControlHandleResponse(reply
, FALSE
, &retry_on_error
);
406 rank
= (SCNetworkServicePrimaryRank
)
407 xpc_dictionary_get_uint64(reply
,
408 kIPMonitorControlResponseKeyPrimaryRank
);
414 if (retry_on_error
) {
419 xpc_release(request
);