Something went wrong. Try again.
Cider Isn't Darwin Emulation, Really
Something went wrong. Try again.
12 kB · 470 lines
C
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471/* * Copyright (c) 2018 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */
/* * Modification History * * January 17, 2018 Dieter Siegmund (dieter@apple.com) * - initial revision */
/* * SCNetworkInterfaceProvider.c */
#include <CoreFoundation/CoreFoundation.h>#include <CoreFoundation/CFRuntime.h>#include <libkern/OSAtomic.h>#include "SCNetworkConfigurationPrivate.h"#include "SCNetworkConfigurationInternal.h"#include "SCNetworkInterfaceProvider.h"
static voidmy_CFRelease(void * t){ void * * obj = (void * *)t; if (obj && *obj) { CFRelease(*obj); *obj = NULL; } return;}
/** ** ObjectWrapper **/
typedef struct { const void * obj; int32_t retain_count;} ObjectWrapper, * ObjectWrapperRef;
static const void *ObjectWrapperRetain(const void * info){ ObjectWrapperRef wrapper = (ObjectWrapperRef)info;
(void)OSAtomicIncrement32(&wrapper->retain_count); return (info);}
static ObjectWrapperRefObjectWrapperAllocate(const void * obj){ ObjectWrapperRef wrapper;
wrapper = (ObjectWrapperRef)malloc(sizeof(*wrapper)); wrapper->obj = obj; wrapper->retain_count = 1; return (wrapper);}
static voidObjectWrapperRelease(const void * info){ int32_t new_val; ObjectWrapperRef wrapper = (ObjectWrapperRef)info;
new_val = OSAtomicDecrement32(&wrapper->retain_count); if (new_val == 0) { free(wrapper); } else { assert(new_val > 0); } return;}
static voidObjectWrapperSetObject(ObjectWrapperRef wrapper, const void * obj){ wrapper->obj = obj;}
static const void *ObjectWrapperGetObject(ObjectWrapperRef wrapper){ return (wrapper->obj);}
static SCDynamicStoreRefStoreObjectWrapperAllocate(const void * obj, CFStringRef name, SCDynamicStoreCallBack handler, CFArrayRef keys, CFArrayRef patterns, dispatch_queue_t queue, ObjectWrapperRef * ret_wrapper){ SCDynamicStoreContext context = { .version = 0, .info = NULL, .retain = ObjectWrapperRetain, .release = ObjectWrapperRelease, .copyDescription = NULL }; SCDynamicStoreRef store; ObjectWrapperRef wrapper;
wrapper = ObjectWrapperAllocate(obj); context.info = wrapper; store = SCDynamicStoreCreate(NULL, name, handler, &context); if (store == NULL) { SC_log(LOG_NOTICE, "%@: SCDynamicStoreCreate failed", name); } else if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns)) { SC_log(LOG_NOTICE, "%@: SCDynamicStoreSetNoticationKeys failed", name); CFRelease(store); store = NULL; } else if (queue != NULL && !SCDynamicStoreSetDispatchQueue(store, queue)) { SC_log(LOG_NOTICE, "%@: SCDynamicStoreSetDispatchQueue failed", name); CFRelease(store); store = NULL; } if (store == NULL) { ObjectWrapperRelease(wrapper); wrapper = NULL; } *ret_wrapper = wrapper; return (store);}
/** ** CF object glue code **/static CFStringRef __SCNetworkInterfaceProviderCopyDebugDesc(CFTypeRef cf);static void __SCNetworkInterfaceProviderDeallocate(CFTypeRef cf);
static CFTypeID __kSCNetworkInterfaceProviderTypeID = _kCFRuntimeNotATypeID;
static const CFRuntimeClass __SCNetworkInterfaceProviderClass = { 0, /* version */ "SCNetworkInterfaceProvider", /* className */ NULL, /* init */ NULL, /* copy */ __SCNetworkInterfaceProviderDeallocate, /* deallocate */ NULL, /* equal */ NULL, /* hash */ NULL, /* copyFormattingDesc */ __SCNetworkInterfaceProviderCopyDebugDesc /* copyDebugDesc */};
struct __SCNetworkInterfaceProvider { CFRuntimeBase cf_base;
IPMonitorControlRef control; SCDynamicStoreRef store; ObjectWrapperRef wrapper; dispatch_queue_t queue;
SCNetworkInterfaceProviderEventHandler handler; CFStringRef if_name; SCNetworkInterfaceRef if_type; Boolean enabled; Boolean needed;};
static CFStringRef__SCNetworkInterfaceProviderCopyDebugDesc(CFTypeRef cf){ CFAllocatorRef allocator = CFGetAllocator(cf); SCNetworkInterfaceProviderRef provider = (SCNetworkInterfaceProviderRef)cf; CFMutableStringRef result;
result = CFStringCreateMutable(allocator, 0); CFStringAppendFormat(result, NULL, CFSTR("<SCNetworkInterfaceProvider %@ %@ <%p>"), provider->if_type, provider->if_name, cf); return (result);}
static voidSCNetworkInterfaceProviderDeallocate(SCNetworkInterfaceProviderRef provider){ provider->enabled = FALSE; my_CFRelease(&provider->control); if (provider->wrapper != NULL) { ObjectWrapperSetObject(provider->wrapper, NULL); ObjectWrapperRelease(provider->wrapper); provider->wrapper = NULL; } if (provider->store != NULL) { SCDynamicStoreSetDispatchQueue(provider->store, NULL); my_CFRelease(&provider->store); } if (provider->queue != NULL) { dispatch_release(provider->queue); provider->queue = NULL; } if (provider->handler != NULL) { Block_release(provider->handler); provider->handler = NULL; } my_CFRelease(&provider->if_name); my_CFRelease(&provider->if_type);}
static void__SCNetworkInterfaceProviderDeallocate(CFTypeRef cf){ SCNetworkInterfaceProviderRef provider = (SCNetworkInterfaceProviderRef)cf;
if (provider->queue != NULL) { dispatch_sync(provider->queue, ^{ SCNetworkInterfaceProviderDeallocate(provider); }); } else { SCNetworkInterfaceProviderDeallocate(provider); } return;}
/** ** Supporting Functions **/static void__SCNetworkInterfaceProviderRegisterClass(void){ static dispatch_once_t once; dispatch_block_t once_block;
once_block = ^{ __kSCNetworkInterfaceProviderTypeID = _CFRuntimeRegisterClass(&__SCNetworkInterfaceProviderClass); }; dispatch_once(&once, once_block); return;}
static SCNetworkInterfaceProviderRef__SCNetworkInterfaceProviderAllocate(CFAllocatorRef allocator){ SCNetworkInterfaceProviderRef provider; int size;
__SCNetworkInterfaceProviderRegisterClass(); size = sizeof(*provider) - sizeof(CFRuntimeBase); provider = (SCNetworkInterfaceProviderRef) _CFRuntimeCreateInstance(allocator, __kSCNetworkInterfaceProviderTypeID, size, NULL); memset(((void *)provider) + sizeof(CFRuntimeBase), 0, size); return (provider);}
static voidSCNetworkInterfaceProviderCheck(SCNetworkInterfaceProviderRef provider){ Boolean advisory_set;
if (!provider->enabled || provider->handler == NULL) { return; } advisory_set = IPMonitorControlAnyInterfaceAdvisoryIsSet(provider->control); if (provider->needed != advisory_set) { SCNetworkInterfaceProviderEvent event;
event = advisory_set ? kSCNetworkInterfaceProviderEventActivationRequested : kSCNetworkInterfaceProviderEventActivationNoLongerRequested; (provider->handler)(event, NULL); provider->needed = advisory_set; } return;}
static voidStoreHandleChanges(SCDynamicStoreRef store, CFArrayRef changes, void * info){#pragma unused(store)#pragma unused(changes) SCNetworkInterfaceProviderRef provider; ObjectWrapperRef wrapper = (ObjectWrapperRef)info;
provider = (SCNetworkInterfaceProviderRef)ObjectWrapperGetObject(wrapper); if (provider == NULL) { /* provider has been deallocated */ return; } SCNetworkInterfaceProviderCheck(provider); return;}
/** ** SCNetworkInterfaceProvider SPI **/SCNetworkInterfaceProviderRefSCNetworkInterfaceProviderCreate(CFStringRef type, CFStringRef ifname, CFDictionaryRef options){ IPMonitorControlRef control; CFStringRef pattern; CFArrayRef patterns; SCNetworkInterfaceProviderRef provider; dispatch_queue_t queue; SCDynamicStoreRef store = NULL; ObjectWrapperRef wrapper = NULL;
if (options != NULL || ifname == NULL || type == NULL) { _SCErrorSet(kSCStatusInvalidArgument); return (NULL); } control = IPMonitorControlCreate(); if (control == NULL) { _SCErrorSet(kSCStatusFailed); return (NULL); } pattern = IPMonitorControlCopyInterfaceAdvisoryNotificationKey(kSCCompAnyRegex); patterns = CFArrayCreate(NULL, (const void * *)&pattern, 1, &kCFTypeArrayCallBacks); CFRelease(pattern);#define OUR_NAME "SCNetworkInterfaceProvider" queue = dispatch_queue_create(OUR_NAME, NULL); provider = __SCNetworkInterfaceProviderAllocate(NULL); store = StoreObjectWrapperAllocate(provider, CFSTR(OUR_NAME), StoreHandleChanges, NULL, patterns, queue, &wrapper); CFRelease(patterns); if (store == NULL) { dispatch_release(queue); CFRelease(provider); provider = NULL; CFRelease(control); } else { provider->control = control; provider->store = store; provider->wrapper = wrapper; provider->queue = queue; provider->if_name = CFRetain(ifname); provider->if_type = CFRetain(type); } return (provider);}
voidSCNetworkInterfaceProviderSetEventHandler(SCNetworkInterfaceProviderRef provider, SCNetworkInterfaceProviderEventHandler handler){ if (handler == NULL) { /* can't clear handler once set */ return; } dispatch_sync(provider->queue, ^{ if (provider->enabled) { /* enabling before setting the handler isn't allowed */ SC_log(LOG_NOTICE, "%s: call SCNetworkInterfaceSetEventHandler before " " SCNetworkInterfaceProviderResume", __FUNCTION__); return; } if (provider->handler != NULL) { /* can't change the handler once set */ SC_log(LOG_NOTICE, "%s: ignoring second invocation of " "SCNetworkInterfaceSetEventHandler", __FUNCTION__); return; } provider->handler = Block_copy(handler); }); return;}
voidSCNetworkInterfaceProviderResume(SCNetworkInterfaceProviderRef provider){ dispatch_async(provider->queue, ^{ if (!provider->enabled) { provider->enabled = TRUE; SCNetworkInterfaceProviderCheck(provider); } }); return;}
#if TEST_SCNetworkInterfaceProvider
/* 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*/
__private_extern__ os_log_t__log_SCNetworkInterfaceProvider(void){ static os_log_t log = NULL;
if (log == NULL) { log = os_log_create("com.apple.SystemConfiguration", "SCNetworkConfiguration"); }
return log;}
static voidevent_handler(SCNetworkInterfaceProviderRef provider, SCNetworkInterfaceProviderEvent event, CFDictionaryRef event_data){ printf("<%p> event %d\n", provider, event);}
intmain(int argc, char * argv[]){ SCNetworkInterfaceProviderEventHandler handler; SCNetworkInterfaceProviderRef provider;
provider = SCNetworkInterfaceProviderCreate(kSCNetworkInterfaceTypeWWAN, CFSTR("pdp_ip10"), NULL); if (provider == NULL) { fprintf(stderr, "SCNetworkInterfaceProviderCreate failed\n"); exit(1); } handler = ^(SCNetworkInterfaceProviderEvent event, CFDictionaryRef event_data) { event_handler(provider, event, event_data); }; SCNetworkInterfaceProviderSetEventHandler(provider, handler); SCNetworkInterfaceProviderResume(provider); dispatch_main(); exit(0); return (0);}#endif