2 * Copyright (c) 2013-2014 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
47 #define my_log(__level, fmt, ...) SCPrint(TRUE, stdout, CFSTR(fmt "\n"), ## __VA_ARGS__)
49 #else /* TEST_IPMONITOR_CONTROL */
51 #define my_log(__level, fmt, ...) SCLog(TRUE, __level, CFSTR(fmt), ## __VA_ARGS__)
52 #endif /* TEST_IPMONITOR_CONTROL */
55 ** IPMonitorControl CF object glue
58 struct IPMonitorControl
{
59 CFRuntimeBase cf_base
;
61 dispatch_queue_t queue
;
62 xpc_connection_t connection
;
63 CFMutableDictionaryRef assertions
; /* ifname<string> = rank<number> */
66 STATIC CFStringRef
__IPMonitorControlCopyDebugDesc(CFTypeRef cf
);
67 STATIC
void __IPMonitorControlDeallocate(CFTypeRef cf
);
69 STATIC CFTypeID __kIPMonitorControlTypeID
= _kCFRuntimeNotATypeID
;
71 STATIC
const CFRuntimeClass __IPMonitorControlClass
= {
73 "IPMonitorControl", /* className */
76 __IPMonitorControlDeallocate
, /* deallocate */
79 NULL
, /* copyFormattingDesc */
80 __IPMonitorControlCopyDebugDesc
/* copyDebugDesc */
84 __IPMonitorControlCopyDebugDesc(CFTypeRef cf
)
86 CFAllocatorRef allocator
= CFGetAllocator(cf
);
87 IPMonitorControlRef control
= (IPMonitorControlRef
)cf
;
89 return (CFStringCreateWithFormat(allocator
, NULL
,
90 CFSTR("<IPMonitorControl %p>"),
95 __IPMonitorControlDeallocate(CFTypeRef cf
)
97 IPMonitorControlRef control
= (IPMonitorControlRef
)cf
;
99 if (control
->connection
!= NULL
) {
100 xpc_release(control
->connection
);
102 if (control
->queue
!= NULL
) {
103 xpc_release(control
->queue
);
109 ** IPMonitorControl support functions
112 __IPMonitorControlRegisterClass(void)
114 STATIC dispatch_once_t once
;
116 dispatch_once(&once
, ^{
117 __kIPMonitorControlTypeID
118 = _CFRuntimeRegisterClass(&__IPMonitorControlClass
);
123 STATIC IPMonitorControlRef
124 __IPMonitorControlAllocate(CFAllocatorRef allocator
)
126 IPMonitorControlRef control
;
129 __IPMonitorControlRegisterClass();
130 size
= sizeof(*control
) - sizeof(CFRuntimeBase
);
131 control
= (IPMonitorControlRef
)
132 _CFRuntimeCreateInstance(allocator
,
133 __kIPMonitorControlTypeID
, size
, NULL
);
134 bzero(((void *)control
) + sizeof(CFRuntimeBase
), size
);
139 IPMonitorControlHandleResponse(xpc_object_t event
, Boolean async
,
142 Boolean retry
= FALSE
;
143 Boolean success
= FALSE
;
146 type
= xpc_get_type(event
);
147 if (type
== XPC_TYPE_DICTIONARY
) {
149 /* we don't expect async responses messages */
150 my_log(LOG_NOTICE
, "IPMonitorControl: unexpected message");
155 error
= xpc_dictionary_get_int64(event
,
156 kIPMonitorControlResponseKeyError
);
159 #ifdef TEST_IPMONITOR_CONTROL
161 "IPMonitorControl: failure code %lld", error
);
162 #endif /* TEST_IPMONITOR_CONTROL */
169 else if (type
== XPC_TYPE_ERROR
) {
170 if (event
== XPC_ERROR_CONNECTION_INTERRUPTED
) {
171 #ifdef TEST_IPMONITOR_CONTROL
172 my_log(LOG_NOTICE
, "IPMonitorControl: can retry");
173 #endif /* TEST_IPMONITOR_CONTROL */
179 desc
= xpc_dictionary_get_string(event
, XPC_ERROR_KEY_DESCRIPTION
);
180 my_log(LOG_NOTICE
, "IPMonitorControl: %s", desc
);
184 my_log(LOG_NOTICE
, "IPMonitorControl: unknown event type : %p", type
);
186 if (retry_p
!= NULL
) {
194 IPMonitorControlSetInterfaceRank(IPMonitorControlRef control
,
195 CFStringRef ifname_cf
,
196 SCNetworkServicePrimaryRank rank
)
198 if (control
->assertions
== NULL
) {
199 if (rank
== kSCNetworkServicePrimaryRankDefault
) {
200 /* no assertions, no need to store rank */
204 = CFDictionaryCreateMutable(NULL
, 0,
205 &kCFTypeDictionaryKeyCallBacks
,
206 &kCFTypeDictionaryValueCallBacks
);
208 if (rank
== kSCNetworkServicePrimaryRankDefault
) {
209 CFDictionaryRemoveValue(control
->assertions
, ifname_cf
);
210 if (CFDictionaryGetCount(control
->assertions
) == 0) {
211 CFRelease(control
->assertions
);
212 control
->assertions
= NULL
;
218 rank_cf
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &rank
);
219 CFDictionarySetValue(control
->assertions
, ifname_cf
, rank_cf
);
226 ApplyInterfaceRank(const void * key
, const void * value
, void * context
)
228 xpc_connection_t connection
= (xpc_connection_t
)context
;
229 char ifname
[IF_NAMESIZE
];
230 SCNetworkServicePrimaryRank rank
;
231 xpc_object_t request
;
233 if (CFStringGetCString(key
, ifname
, sizeof(ifname
),
234 kCFStringEncodingUTF8
) == FALSE
) {
237 if (CFNumberGetValue(value
, kCFNumberSInt32Type
, &rank
) == FALSE
) {
240 request
= xpc_dictionary_create(NULL
, NULL
, 0);
241 xpc_dictionary_set_uint64(request
,
242 kIPMonitorControlRequestKeyType
,
243 kIPMonitorControlRequestTypeSetInterfaceRank
);
244 xpc_dictionary_set_string(request
,
245 kIPMonitorControlRequestKeyInterfaceName
,
247 xpc_dictionary_set_uint64(request
,
248 kIPMonitorControlRequestKeyPrimaryRank
,
250 xpc_connection_send_message(connection
, request
);
251 xpc_release(request
);
257 ** IPMonitorControl SPI
259 PRIVATE_EXTERN IPMonitorControlRef
260 IPMonitorControlCreate(void)
262 xpc_connection_t connection
;
263 IPMonitorControlRef control
;
264 uint64_t flags
= XPC_CONNECTION_MACH_SERVICE_PRIVILEGED
;
265 xpc_handler_t handler
;
266 dispatch_queue_t queue
;
268 control
= __IPMonitorControlAllocate(NULL
);
269 queue
= dispatch_queue_create("IPMonitorControl", NULL
);
271 = xpc_connection_create_mach_service(kIPMonitorControlServerName
,
273 handler
= ^(xpc_object_t event
) {
276 (void)IPMonitorControlHandleResponse(event
, TRUE
, &retry
);
277 if (retry
&& control
->assertions
!= NULL
) {
278 CFDictionaryApplyFunction(control
->assertions
,
280 control
->connection
);
283 xpc_connection_set_event_handler(connection
, handler
);
284 control
->connection
= connection
;
285 control
->queue
= queue
;
286 xpc_connection_resume(connection
);
290 PRIVATE_EXTERN Boolean
291 IPMonitorControlSetInterfacePrimaryRank(IPMonitorControlRef control
,
292 CFStringRef ifname_cf
,
293 SCNetworkServicePrimaryRank rank
)
295 char ifname
[IF_NAMESIZE
];
296 xpc_object_t request
;
297 Boolean success
= FALSE
;
299 if (CFStringGetCString(ifname_cf
, ifname
, sizeof(ifname
),
300 kCFStringEncodingUTF8
) == FALSE
) {
303 request
= xpc_dictionary_create(NULL
, NULL
, 0);
304 xpc_dictionary_set_uint64(request
,
305 kIPMonitorControlRequestKeyType
,
306 kIPMonitorControlRequestTypeSetInterfaceRank
);
307 xpc_dictionary_set_string(request
,
308 kIPMonitorControlRequestKeyInterfaceName
,
310 xpc_dictionary_set_uint64(request
,
311 kIPMonitorControlRequestKeyPrimaryRank
,
315 Boolean retry_on_error
= FALSE
;
317 reply
= xpc_connection_send_message_with_reply_sync(control
->connection
,
320 my_log(LOG_NOTICE
, "IPMonitorControl: failed to send message");
323 success
= IPMonitorControlHandleResponse(reply
, FALSE
,
329 if (retry_on_error
) {
332 my_log(LOG_NOTICE
, "IPMonitorControl: fatal error");
335 xpc_release(request
);
340 dispatch_async(control
->queue
,
342 IPMonitorControlSetInterfaceRank(control
,
345 CFRelease(ifname_cf
);
352 SCNetworkServicePrimaryRank
353 IPMonitorControlGetInterfacePrimaryRank(IPMonitorControlRef control
,
354 CFStringRef ifname_cf
)
356 char ifname
[IF_NAMESIZE
];
357 SCNetworkServicePrimaryRank rank
;
358 xpc_object_t request
;
360 rank
= kSCNetworkServicePrimaryRankDefault
;
361 if (CFStringGetCString(ifname_cf
, ifname
, sizeof(ifname
),
362 kCFStringEncodingUTF8
) == FALSE
) {
365 request
= xpc_dictionary_create(NULL
, NULL
, 0);
366 xpc_dictionary_set_uint64(request
,
367 kIPMonitorControlRequestKeyType
,
368 kIPMonitorControlRequestTypeGetInterfaceRank
);
369 xpc_dictionary_set_string(request
,
370 kIPMonitorControlRequestKeyInterfaceName
,
374 Boolean retry_on_error
= FALSE
;
377 reply
= xpc_connection_send_message_with_reply_sync(control
->connection
,
380 my_log(LOG_NOTICE
, "IPMonitorControl: failed to send message");
383 success
= IPMonitorControlHandleResponse(reply
, FALSE
, &retry_on_error
);
385 rank
= (SCNetworkServicePrimaryRank
)
386 xpc_dictionary_get_uint64(reply
,
387 kIPMonitorControlResponseKeyPrimaryRank
);
393 if (retry_on_error
) {
398 xpc_release(request
);