2 * Copyright (c) 2018 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@
25 * Modification History
27 * January 17, 2018 Dieter Siegmund (dieter@apple.com)
32 * SCNetworkInterfaceProvider.c
35 #include <CoreFoundation/CoreFoundation.h>
36 #include <CoreFoundation/CFRuntime.h>
37 #include <libkern/OSAtomic.h>
38 #include "SCNetworkConfigurationPrivate.h"
39 #include "SCNetworkConfigurationInternal.h"
40 #include "SCNetworkInterfaceProvider.h"
43 my_CFRelease(void * t
)
45 void * * obj
= (void * *)t
;
60 } ObjectWrapper
, * ObjectWrapperRef
;
63 ObjectWrapperRetain(const void * info
)
65 ObjectWrapperRef wrapper
= (ObjectWrapperRef
)info
;
67 (void)OSAtomicIncrement32(&wrapper
->retain_count
);
71 static ObjectWrapperRef
72 ObjectWrapperAllocate(const void * obj
)
74 ObjectWrapperRef wrapper
;
76 wrapper
= (ObjectWrapperRef
)malloc(sizeof(*wrapper
));
78 wrapper
->retain_count
= 1;
83 ObjectWrapperRelease(const void * info
)
86 ObjectWrapperRef wrapper
= (ObjectWrapperRef
)info
;
88 new_val
= OSAtomicDecrement32(&wrapper
->retain_count
);
99 ObjectWrapperSetObject(ObjectWrapperRef wrapper
, const void * obj
)
105 ObjectWrapperGetObject(ObjectWrapperRef wrapper
)
107 return (wrapper
->obj
);
110 static SCDynamicStoreRef
111 StoreObjectWrapperAllocate(const void * obj
,
113 SCDynamicStoreCallBack handler
,
116 dispatch_queue_t queue
,
117 ObjectWrapperRef
* ret_wrapper
)
119 SCDynamicStoreContext context
= {
122 .retain
= ObjectWrapperRetain
,
123 .release
= ObjectWrapperRelease
,
124 .copyDescription
= NULL
126 SCDynamicStoreRef store
;
127 ObjectWrapperRef wrapper
;
129 wrapper
= ObjectWrapperAllocate(obj
);
130 context
.info
= wrapper
;
131 store
= SCDynamicStoreCreate(NULL
, name
, handler
, &context
);
134 "%@: SCDynamicStoreCreate failed", name
);
136 else if (!SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
)) {
138 "%@: SCDynamicStoreSetNoticationKeys failed", name
);
142 else if (queue
!= NULL
143 && !SCDynamicStoreSetDispatchQueue(store
, queue
)) {
145 "%@: SCDynamicStoreSetDispatchQueue failed", name
);
150 ObjectWrapperRelease(wrapper
);
153 *ret_wrapper
= wrapper
;
158 ** CF object glue code
160 static CFStringRef
__SCNetworkInterfaceProviderCopyDebugDesc(CFTypeRef cf
);
161 static void __SCNetworkInterfaceProviderDeallocate(CFTypeRef cf
);
163 static CFTypeID __kSCNetworkInterfaceProviderTypeID
= _kCFRuntimeNotATypeID
;
165 static const CFRuntimeClass __SCNetworkInterfaceProviderClass
= {
167 "SCNetworkInterfaceProvider", /* className */
170 __SCNetworkInterfaceProviderDeallocate
, /* deallocate */
173 NULL
, /* copyFormattingDesc */
174 __SCNetworkInterfaceProviderCopyDebugDesc
/* copyDebugDesc */
177 struct __SCNetworkInterfaceProvider
{
178 CFRuntimeBase cf_base
;
180 IPMonitorControlRef control
;
181 SCDynamicStoreRef store
;
182 ObjectWrapperRef wrapper
;
183 dispatch_queue_t queue
;
185 SCNetworkInterfaceProviderEventHandler handler
;
187 SCNetworkInterfaceRef if_type
;
194 __SCNetworkInterfaceProviderCopyDebugDesc(CFTypeRef cf
)
196 CFAllocatorRef allocator
= CFGetAllocator(cf
);
197 SCNetworkInterfaceProviderRef provider
= (SCNetworkInterfaceProviderRef
)cf
;
198 CFMutableStringRef result
;
200 result
= CFStringCreateMutable(allocator
, 0);
201 CFStringAppendFormat(result
, NULL
,
202 CFSTR("<SCNetworkInterfaceProvider %@ %@ <%p>"),
203 provider
->if_type
, provider
->if_name
, cf
);
208 SCNetworkInterfaceProviderDeallocate(SCNetworkInterfaceProviderRef provider
)
210 provider
->enabled
= FALSE
;
211 my_CFRelease(&provider
->control
);
212 if (provider
->wrapper
!= NULL
) {
213 ObjectWrapperSetObject(provider
->wrapper
, NULL
);
214 ObjectWrapperRelease(provider
->wrapper
);
215 provider
->wrapper
= NULL
;
217 if (provider
->store
!= NULL
) {
218 SCDynamicStoreSetDispatchQueue(provider
->store
, NULL
);
219 my_CFRelease(&provider
->store
);
221 if (provider
->queue
!= NULL
) {
222 dispatch_release(provider
->queue
);
223 provider
->queue
= NULL
;
225 if (provider
->handler
!= NULL
) {
226 Block_release(provider
->handler
);
227 provider
->handler
= NULL
;
229 my_CFRelease(&provider
->if_name
);
230 my_CFRelease(&provider
->if_type
);
234 __SCNetworkInterfaceProviderDeallocate(CFTypeRef cf
)
236 SCNetworkInterfaceProviderRef provider
= (SCNetworkInterfaceProviderRef
)cf
;
238 if (provider
->queue
!= NULL
) {
239 dispatch_sync(provider
->queue
, ^{
240 SCNetworkInterfaceProviderDeallocate(provider
);
244 SCNetworkInterfaceProviderDeallocate(provider
);
250 ** Supporting Functions
253 __SCNetworkInterfaceProviderRegisterClass(void)
255 static dispatch_once_t once
;
256 dispatch_block_t once_block
;
259 __kSCNetworkInterfaceProviderTypeID
260 = _CFRuntimeRegisterClass(&__SCNetworkInterfaceProviderClass
);
262 dispatch_once(&once
, once_block
);
266 static SCNetworkInterfaceProviderRef
267 __SCNetworkInterfaceProviderAllocate(CFAllocatorRef allocator
)
269 SCNetworkInterfaceProviderRef provider
;
272 __SCNetworkInterfaceProviderRegisterClass();
273 size
= sizeof(*provider
) - sizeof(CFRuntimeBase
);
274 provider
= (SCNetworkInterfaceProviderRef
)
275 _CFRuntimeCreateInstance(allocator
,
276 __kSCNetworkInterfaceProviderTypeID
,
278 memset(((void *)provider
) + sizeof(CFRuntimeBase
), 0, size
);
283 SCNetworkInterfaceProviderCheck(SCNetworkInterfaceProviderRef provider
)
285 Boolean advisory_set
;
287 if (!provider
->enabled
|| provider
->handler
== NULL
) {
291 = IPMonitorControlAnyInterfaceAdvisoryIsSet(provider
->control
);
292 if (provider
->needed
!= advisory_set
) {
293 SCNetworkInterfaceProviderEvent event
;
296 ? kSCNetworkInterfaceProviderEventActivationRequested
297 : kSCNetworkInterfaceProviderEventActivationNoLongerRequested
;
298 (provider
->handler
)(event
, NULL
);
299 provider
->needed
= advisory_set
;
305 StoreHandleChanges(SCDynamicStoreRef store
, CFArrayRef changes
, void * info
)
307 #pragma unused(store)
308 #pragma unused(changes)
309 SCNetworkInterfaceProviderRef provider
;
310 ObjectWrapperRef wrapper
= (ObjectWrapperRef
)info
;
312 provider
= (SCNetworkInterfaceProviderRef
)ObjectWrapperGetObject(wrapper
);
313 if (provider
== NULL
) {
314 /* provider has been deallocated */
317 SCNetworkInterfaceProviderCheck(provider
);
323 ** SCNetworkInterfaceProvider SPI
325 SCNetworkInterfaceProviderRef
326 SCNetworkInterfaceProviderCreate(CFStringRef type
,
328 CFDictionaryRef options
)
330 IPMonitorControlRef control
;
333 SCNetworkInterfaceProviderRef provider
;
334 dispatch_queue_t queue
;
335 SCDynamicStoreRef store
= NULL
;
336 ObjectWrapperRef wrapper
= NULL
;
338 if (options
!= NULL
|| ifname
== NULL
|| type
== NULL
) {
339 _SCErrorSet(kSCStatusInvalidArgument
);
342 control
= IPMonitorControlCreate();
343 if (control
== NULL
) {
344 _SCErrorSet(kSCStatusFailed
);
348 = IPMonitorControlCopyInterfaceAdvisoryNotificationKey(kSCCompAnyRegex
);
349 patterns
= CFArrayCreate(NULL
, (const void * *)&pattern
, 1,
350 &kCFTypeArrayCallBacks
);
352 #define OUR_NAME "SCNetworkInterfaceProvider"
353 queue
= dispatch_queue_create(OUR_NAME
, NULL
);
354 provider
= __SCNetworkInterfaceProviderAllocate(NULL
);
355 store
= StoreObjectWrapperAllocate(provider
,
364 dispatch_release(queue
);
370 provider
->control
= control
;
371 provider
->store
= store
;
372 provider
->wrapper
= wrapper
;
373 provider
->queue
= queue
;
374 provider
->if_name
= CFRetain(ifname
);
375 provider
->if_type
= CFRetain(type
);
381 SCNetworkInterfaceProviderSetEventHandler(SCNetworkInterfaceProviderRef provider
,
382 SCNetworkInterfaceProviderEventHandler handler
)
384 if (handler
== NULL
) {
385 /* can't clear handler once set */
388 dispatch_sync(provider
->queue
, ^{
389 if (provider
->enabled
) {
390 /* enabling before setting the handler isn't allowed */
392 "%s: call SCNetworkInterfaceSetEventHandler before "
393 " SCNetworkInterfaceProviderResume", __FUNCTION__
);
396 if (provider
->handler
!= NULL
) {
397 /* can't change the handler once set */
399 "%s: ignoring second invocation of "
400 "SCNetworkInterfaceSetEventHandler", __FUNCTION__
);
403 provider
->handler
= Block_copy(handler
);
409 SCNetworkInterfaceProviderResume(SCNetworkInterfaceProviderRef provider
)
411 dispatch_async(provider
->queue
, ^{
412 if (!provider
->enabled
) {
413 provider
->enabled
= TRUE
;
414 SCNetworkInterfaceProviderCheck(provider
);
420 #if TEST_SCNetworkInterfaceProvider
423 xcrun -sdk iphoneos.internal cc -o scnip SCNetworkInterfaceProvider.c -DTEST_SCNetworkInterfaceProvider -framework CoreFoundation -framework SystemConfiguration -arch arm64 -I ../IPMonitorControl ../IPMonitorControl/IPMonitorControl.c -DSC_LOG_HANDLE=__log_SCNetworkInterfaceProvider
426 __private_extern__ os_log_t
427 __log_SCNetworkInterfaceProvider(void)
429 static os_log_t log
= NULL
;
432 log
= os_log_create("com.apple.SystemConfiguration", "SCNetworkConfiguration");
439 event_handler(SCNetworkInterfaceProviderRef provider
,
440 SCNetworkInterfaceProviderEvent event
,
441 CFDictionaryRef event_data
)
443 printf("<%p> event %d\n", provider
, event
);
447 main(int argc
, char * argv
[])
449 SCNetworkInterfaceProviderEventHandler handler
;
450 SCNetworkInterfaceProviderRef provider
;
453 = SCNetworkInterfaceProviderCreate(kSCNetworkInterfaceTypeWWAN
,
456 if (provider
== NULL
) {
457 fprintf(stderr
, "SCNetworkInterfaceProviderCreate failed\n");
460 handler
= ^(SCNetworkInterfaceProviderEvent event
,
461 CFDictionaryRef event_data
) {
462 event_handler(provider
, event
, event_data
);
464 SCNetworkInterfaceProviderSetEventHandler(provider
, handler
);
465 SCNetworkInterfaceProviderResume(provider
);