this repo has no description
at fixPythonPipStalling 470 lines 12 kB view raw
1/* 2 * Copyright (c) 2018 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 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 11 * file. 12 * 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. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * Modification History 26 * 27 * January 17, 2018 Dieter Siegmund (dieter@apple.com) 28 * - initial revision 29 */ 30 31/* 32 * SCNetworkInterfaceProvider.c 33 */ 34 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" 41 42static void 43my_CFRelease(void * t) 44{ 45 void * * obj = (void * *)t; 46 if (obj && *obj) { 47 CFRelease(*obj); 48 *obj = NULL; 49 } 50 return; 51} 52 53/** 54 ** ObjectWrapper 55 **/ 56 57typedef struct { 58 const void * obj; 59 int32_t retain_count; 60} ObjectWrapper, * ObjectWrapperRef; 61 62static const void * 63ObjectWrapperRetain(const void * info) 64{ 65 ObjectWrapperRef wrapper = (ObjectWrapperRef)info; 66 67 (void)OSAtomicIncrement32(&wrapper->retain_count); 68 return (info); 69} 70 71static ObjectWrapperRef 72ObjectWrapperAllocate(const void * obj) 73{ 74 ObjectWrapperRef wrapper; 75 76 wrapper = (ObjectWrapperRef)malloc(sizeof(*wrapper)); 77 wrapper->obj = obj; 78 wrapper->retain_count = 1; 79 return (wrapper); 80} 81 82static void 83ObjectWrapperRelease(const void * info) 84{ 85 int32_t new_val; 86 ObjectWrapperRef wrapper = (ObjectWrapperRef)info; 87 88 new_val = OSAtomicDecrement32(&wrapper->retain_count); 89 if (new_val == 0) { 90 free(wrapper); 91 } 92 else { 93 assert(new_val > 0); 94 } 95 return; 96} 97 98static void 99ObjectWrapperSetObject(ObjectWrapperRef wrapper, const void * obj) 100{ 101 wrapper->obj = obj; 102} 103 104static const void * 105ObjectWrapperGetObject(ObjectWrapperRef wrapper) 106{ 107 return (wrapper->obj); 108} 109 110static SCDynamicStoreRef 111StoreObjectWrapperAllocate(const void * obj, 112 CFStringRef name, 113 SCDynamicStoreCallBack handler, 114 CFArrayRef keys, 115 CFArrayRef patterns, 116 dispatch_queue_t queue, 117 ObjectWrapperRef * ret_wrapper) 118{ 119 SCDynamicStoreContext context = { 120 .version = 0, 121 .info = NULL, 122 .retain = ObjectWrapperRetain, 123 .release = ObjectWrapperRelease, 124 .copyDescription = NULL 125 }; 126 SCDynamicStoreRef store; 127 ObjectWrapperRef wrapper; 128 129 wrapper = ObjectWrapperAllocate(obj); 130 context.info = wrapper; 131 store = SCDynamicStoreCreate(NULL, name, handler, &context); 132 if (store == NULL) { 133 SC_log(LOG_NOTICE, 134 "%@: SCDynamicStoreCreate failed", name); 135 } 136 else if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns)) { 137 SC_log(LOG_NOTICE, 138 "%@: SCDynamicStoreSetNoticationKeys failed", name); 139 CFRelease(store); 140 store = NULL; 141 } 142 else if (queue != NULL 143 && !SCDynamicStoreSetDispatchQueue(store, queue)) { 144 SC_log(LOG_NOTICE, 145 "%@: SCDynamicStoreSetDispatchQueue failed", name); 146 CFRelease(store); 147 store = NULL; 148 } 149 if (store == NULL) { 150 ObjectWrapperRelease(wrapper); 151 wrapper = NULL; 152 } 153 *ret_wrapper = wrapper; 154 return (store); 155} 156 157/** 158 ** CF object glue code 159 **/ 160static CFStringRef __SCNetworkInterfaceProviderCopyDebugDesc(CFTypeRef cf); 161static void __SCNetworkInterfaceProviderDeallocate(CFTypeRef cf); 162 163static CFTypeID __kSCNetworkInterfaceProviderTypeID = _kCFRuntimeNotATypeID; 164 165static const CFRuntimeClass __SCNetworkInterfaceProviderClass = { 166 0, /* version */ 167 "SCNetworkInterfaceProvider", /* className */ 168 NULL, /* init */ 169 NULL, /* copy */ 170 __SCNetworkInterfaceProviderDeallocate, /* deallocate */ 171 NULL, /* equal */ 172 NULL, /* hash */ 173 NULL, /* copyFormattingDesc */ 174 __SCNetworkInterfaceProviderCopyDebugDesc /* copyDebugDesc */ 175}; 176 177struct __SCNetworkInterfaceProvider { 178 CFRuntimeBase cf_base; 179 180 IPMonitorControlRef control; 181 SCDynamicStoreRef store; 182 ObjectWrapperRef wrapper; 183 dispatch_queue_t queue; 184 185 SCNetworkInterfaceProviderEventHandler handler; 186 CFStringRef if_name; 187 SCNetworkInterfaceRef if_type; 188 Boolean enabled; 189 Boolean needed; 190}; 191 192 193static CFStringRef 194__SCNetworkInterfaceProviderCopyDebugDesc(CFTypeRef cf) 195{ 196 CFAllocatorRef allocator = CFGetAllocator(cf); 197 SCNetworkInterfaceProviderRef provider = (SCNetworkInterfaceProviderRef)cf; 198 CFMutableStringRef result; 199 200 result = CFStringCreateMutable(allocator, 0); 201 CFStringAppendFormat(result, NULL, 202 CFSTR("<SCNetworkInterfaceProvider %@ %@ <%p>"), 203 provider->if_type, provider->if_name, cf); 204 return (result); 205} 206 207static void 208SCNetworkInterfaceProviderDeallocate(SCNetworkInterfaceProviderRef provider) 209{ 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; 216 } 217 if (provider->store != NULL) { 218 SCDynamicStoreSetDispatchQueue(provider->store, NULL); 219 my_CFRelease(&provider->store); 220 } 221 if (provider->queue != NULL) { 222 dispatch_release(provider->queue); 223 provider->queue = NULL; 224 } 225 if (provider->handler != NULL) { 226 Block_release(provider->handler); 227 provider->handler = NULL; 228 } 229 my_CFRelease(&provider->if_name); 230 my_CFRelease(&provider->if_type); 231} 232 233static void 234__SCNetworkInterfaceProviderDeallocate(CFTypeRef cf) 235{ 236 SCNetworkInterfaceProviderRef provider = (SCNetworkInterfaceProviderRef)cf; 237 238 if (provider->queue != NULL) { 239 dispatch_sync(provider->queue, ^{ 240 SCNetworkInterfaceProviderDeallocate(provider); 241 }); 242 } 243 else { 244 SCNetworkInterfaceProviderDeallocate(provider); 245 } 246 return; 247} 248 249/** 250 ** Supporting Functions 251 **/ 252static void 253__SCNetworkInterfaceProviderRegisterClass(void) 254{ 255 static dispatch_once_t once; 256 dispatch_block_t once_block; 257 258 once_block = ^{ 259 __kSCNetworkInterfaceProviderTypeID 260 = _CFRuntimeRegisterClass(&__SCNetworkInterfaceProviderClass); 261 }; 262 dispatch_once(&once, once_block); 263 return; 264} 265 266static SCNetworkInterfaceProviderRef 267__SCNetworkInterfaceProviderAllocate(CFAllocatorRef allocator) 268{ 269 SCNetworkInterfaceProviderRef provider; 270 int size; 271 272 __SCNetworkInterfaceProviderRegisterClass(); 273 size = sizeof(*provider) - sizeof(CFRuntimeBase); 274 provider = (SCNetworkInterfaceProviderRef) 275 _CFRuntimeCreateInstance(allocator, 276 __kSCNetworkInterfaceProviderTypeID, 277 size, NULL); 278 memset(((void *)provider) + sizeof(CFRuntimeBase), 0, size); 279 return (provider); 280} 281 282static void 283SCNetworkInterfaceProviderCheck(SCNetworkInterfaceProviderRef provider) 284{ 285 Boolean advisory_set; 286 287 if (!provider->enabled || provider->handler == NULL) { 288 return; 289 } 290 advisory_set 291 = IPMonitorControlAnyInterfaceAdvisoryIsSet(provider->control); 292 if (provider->needed != advisory_set) { 293 SCNetworkInterfaceProviderEvent event; 294 295 event = advisory_set 296 ? kSCNetworkInterfaceProviderEventActivationRequested 297 : kSCNetworkInterfaceProviderEventActivationNoLongerRequested; 298 (provider->handler)(event, NULL); 299 provider->needed = advisory_set; 300 } 301 return; 302} 303 304static void 305StoreHandleChanges(SCDynamicStoreRef store, CFArrayRef changes, void * info) 306{ 307#pragma unused(store) 308#pragma unused(changes) 309 SCNetworkInterfaceProviderRef provider; 310 ObjectWrapperRef wrapper = (ObjectWrapperRef)info; 311 312 provider = (SCNetworkInterfaceProviderRef)ObjectWrapperGetObject(wrapper); 313 if (provider == NULL) { 314 /* provider has been deallocated */ 315 return; 316 } 317 SCNetworkInterfaceProviderCheck(provider); 318 return; 319} 320 321 322/** 323 ** SCNetworkInterfaceProvider SPI 324 **/ 325SCNetworkInterfaceProviderRef 326SCNetworkInterfaceProviderCreate(CFStringRef type, 327 CFStringRef ifname, 328 CFDictionaryRef options) 329{ 330 IPMonitorControlRef control; 331 CFStringRef pattern; 332 CFArrayRef patterns; 333 SCNetworkInterfaceProviderRef provider; 334 dispatch_queue_t queue; 335 SCDynamicStoreRef store = NULL; 336 ObjectWrapperRef wrapper = NULL; 337 338 if (options != NULL || ifname == NULL || type == NULL) { 339 _SCErrorSet(kSCStatusInvalidArgument); 340 return (NULL); 341 } 342 control = IPMonitorControlCreate(); 343 if (control == NULL) { 344 _SCErrorSet(kSCStatusFailed); 345 return (NULL); 346 } 347 pattern 348 = IPMonitorControlCopyInterfaceAdvisoryNotificationKey(kSCCompAnyRegex); 349 patterns = CFArrayCreate(NULL, (const void * *)&pattern, 1, 350 &kCFTypeArrayCallBacks); 351 CFRelease(pattern); 352#define OUR_NAME "SCNetworkInterfaceProvider" 353 queue = dispatch_queue_create(OUR_NAME, NULL); 354 provider = __SCNetworkInterfaceProviderAllocate(NULL); 355 store = StoreObjectWrapperAllocate(provider, 356 CFSTR(OUR_NAME), 357 StoreHandleChanges, 358 NULL, 359 patterns, 360 queue, 361 &wrapper); 362 CFRelease(patterns); 363 if (store == NULL) { 364 dispatch_release(queue); 365 CFRelease(provider); 366 provider = NULL; 367 CFRelease(control); 368 } 369 else { 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); 376 } 377 return (provider); 378} 379 380void 381SCNetworkInterfaceProviderSetEventHandler(SCNetworkInterfaceProviderRef provider, 382 SCNetworkInterfaceProviderEventHandler handler) 383{ 384 if (handler == NULL) { 385 /* can't clear handler once set */ 386 return; 387 } 388 dispatch_sync(provider->queue, ^{ 389 if (provider->enabled) { 390 /* enabling before setting the handler isn't allowed */ 391 SC_log(LOG_NOTICE, 392 "%s: call SCNetworkInterfaceSetEventHandler before " 393 " SCNetworkInterfaceProviderResume", __FUNCTION__); 394 return; 395 } 396 if (provider->handler != NULL) { 397 /* can't change the handler once set */ 398 SC_log(LOG_NOTICE, 399 "%s: ignoring second invocation of " 400 "SCNetworkInterfaceSetEventHandler", __FUNCTION__); 401 return; 402 } 403 provider->handler = Block_copy(handler); 404 }); 405 return; 406} 407 408void 409SCNetworkInterfaceProviderResume(SCNetworkInterfaceProviderRef provider) 410{ 411 dispatch_async(provider->queue, ^{ 412 if (!provider->enabled) { 413 provider->enabled = TRUE; 414 SCNetworkInterfaceProviderCheck(provider); 415 } 416 }); 417 return; 418} 419 420#if TEST_SCNetworkInterfaceProvider 421 422/* 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 424*/ 425 426__private_extern__ os_log_t 427__log_SCNetworkInterfaceProvider(void) 428{ 429 static os_log_t log = NULL; 430 431 if (log == NULL) { 432 log = os_log_create("com.apple.SystemConfiguration", "SCNetworkConfiguration"); 433 } 434 435 return log; 436} 437 438static void 439event_handler(SCNetworkInterfaceProviderRef provider, 440 SCNetworkInterfaceProviderEvent event, 441 CFDictionaryRef event_data) 442{ 443 printf("<%p> event %d\n", provider, event); 444} 445 446int 447main(int argc, char * argv[]) 448{ 449 SCNetworkInterfaceProviderEventHandler handler; 450 SCNetworkInterfaceProviderRef provider; 451 452 provider 453 = SCNetworkInterfaceProviderCreate(kSCNetworkInterfaceTypeWWAN, 454 CFSTR("pdp_ip10"), 455 NULL); 456 if (provider == NULL) { 457 fprintf(stderr, "SCNetworkInterfaceProviderCreate failed\n"); 458 exit(1); 459 } 460 handler = ^(SCNetworkInterfaceProviderEvent event, 461 CFDictionaryRef event_data) { 462 event_handler(provider, event, event_data); 463 }; 464 SCNetworkInterfaceProviderSetEventHandler(provider, handler); 465 SCNetworkInterfaceProviderResume(provider); 466 dispatch_main(); 467 exit(0); 468 return (0); 469} 470#endif