this repo has no description
at fixPythonPipStalling 605 lines 16 kB view raw
1/* 2 * Copyright (c) 2013-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 * IPMonitorControl.c 26 * - IPC channel to IPMonitor 27 * - used to create interface rank assertions 28 */ 29 30/* 31 * Modification History 32 * 33 * December 16, 2013 Dieter Siegmund (dieter@apple.com) 34 * - initial revision 35 */ 36 37#include "IPMonitorControl.h" 38#include "IPMonitorControlPrivate.h" 39#include "symbol_scope.h" 40#include <CoreFoundation/CFRuntime.h> 41#include <net/if.h> 42#include <xpc/xpc.h> 43#include <xpc/private.h> 44#include <SystemConfiguration/SCPrivate.h> 45 46#ifdef TEST_IPMONITOR_CONTROL 47 48#define my_log(__level, __format, ...) SCPrint(TRUE, stdout, CFSTR(__format "\n"), ## __VA_ARGS__) 49 50#else /* TEST_IPMONITOR_CONTROL */ 51 52#define my_log(__level, __format, ...) SC_log(__level, __format, ## __VA_ARGS__) 53 54#endif /* TEST_IPMONITOR_CONTROL */ 55 56/** 57 ** IPMonitorControl CF object glue 58 **/ 59 60struct IPMonitorControl { 61 CFRuntimeBase cf_base; 62 63 dispatch_queue_t queue; 64 xpc_connection_t connection; 65 66 CFMutableDictionaryRef assertions; /* ifname<string> = rank<number> */ 67 CFMutableDictionaryRef advisories; /* ifname<string> = adv<number> */ 68}; 69 70STATIC CFStringRef __IPMonitorControlCopyDebugDesc(CFTypeRef cf); 71STATIC void __IPMonitorControlDeallocate(CFTypeRef cf); 72 73STATIC CFTypeID __kIPMonitorControlTypeID = _kCFRuntimeNotATypeID; 74 75STATIC const CFRuntimeClass __IPMonitorControlClass = { 76 0, /* version */ 77 "IPMonitorControl", /* className */ 78 NULL, /* init */ 79 NULL, /* copy */ 80 __IPMonitorControlDeallocate, /* deallocate */ 81 NULL, /* equal */ 82 NULL, /* hash */ 83 NULL, /* copyFormattingDesc */ 84 __IPMonitorControlCopyDebugDesc /* copyDebugDesc */ 85}; 86 87STATIC CFStringRef 88__IPMonitorControlCopyDebugDesc(CFTypeRef cf) 89{ 90 CFAllocatorRef allocator = CFGetAllocator(cf); 91 IPMonitorControlRef control = (IPMonitorControlRef)cf; 92 93 return (CFStringCreateWithFormat(allocator, NULL, 94 CFSTR("<IPMonitorControl %p>"), 95 control)); 96} 97 98STATIC void 99__IPMonitorControlDeallocate(CFTypeRef cf) 100{ 101 IPMonitorControlRef control = (IPMonitorControlRef)cf; 102 103 if (control->connection != NULL) { 104 xpc_release(control->connection); 105 } 106 if (control->queue != NULL) { 107 dispatch_release(control->queue); 108 } 109 my_CFRelease(&control->advisories); 110 my_CFRelease(&control->assertions); 111 return; 112} 113 114/** 115 ** IPMonitorControl support functions 116 **/ 117STATIC void 118__IPMonitorControlRegisterClass(void) 119{ 120 STATIC dispatch_once_t once; 121 122 dispatch_once(&once, ^{ 123 __kIPMonitorControlTypeID 124 = _CFRuntimeRegisterClass(&__IPMonitorControlClass); 125 }); 126 return; 127} 128 129STATIC IPMonitorControlRef 130__IPMonitorControlAllocate(CFAllocatorRef allocator) 131{ 132 IPMonitorControlRef control; 133 int size; 134 135 __IPMonitorControlRegisterClass(); 136 size = sizeof(*control) - sizeof(CFRuntimeBase); 137 control = (IPMonitorControlRef) 138 _CFRuntimeCreateInstance(allocator, 139 __kIPMonitorControlTypeID, size, NULL); 140 return (control); 141} 142 143STATIC xpc_object_t 144create_request_dictionary(void) 145{ 146 const char * progname; 147 xpc_object_t request; 148 149 request = xpc_dictionary_create(NULL, NULL, 0); 150 progname = getprogname(); 151 if (progname != NULL) { 152 xpc_dictionary_set_string(request, 153 kIPMonitorControlRequestKeyProcessName, 154 progname); 155 } 156 return (request); 157} 158 159STATIC Boolean 160IPMonitorControlHandleResponse(xpc_object_t event, Boolean async, 161 Boolean * retry_p) 162{ 163 Boolean retry = FALSE; 164 Boolean success = FALSE; 165 xpc_type_t type; 166 167 type = xpc_get_type(event); 168 if (type == XPC_TYPE_DICTIONARY) { 169 if (async) { 170 /* we don't expect async responses messages */ 171 my_log(LOG_NOTICE, "unexpected message"); 172 } 173 else { 174 int64_t error; 175 176 error = xpc_dictionary_get_int64(event, 177 kIPMonitorControlResponseKeyError); 178 if (error != 0) { 179 success = FALSE; 180#ifdef TEST_IPMONITOR_CONTROL 181 my_log(LOG_NOTICE, "failure code %lld", error); 182#endif /* TEST_IPMONITOR_CONTROL */ 183 } 184 else { 185 success = TRUE; 186 } 187 } 188 } 189 else if (type == XPC_TYPE_ERROR) { 190 if (event == XPC_ERROR_CONNECTION_INTERRUPTED) { 191#ifdef TEST_IPMONITOR_CONTROL 192 my_log(LOG_NOTICE, "can retry"); 193#endif /* TEST_IPMONITOR_CONTROL */ 194 retry = TRUE; 195 } 196 else { 197 const char * desc; 198 199 desc = xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION); 200 my_log(LOG_NOTICE, "%s", desc); 201 } 202 } 203 else { 204 my_log(LOG_NOTICE, "unknown event type : %p", type); 205 } 206 if (retry_p != NULL) { 207 *retry_p = retry; 208 } 209 return (success); 210} 211 212 213STATIC void 214_IPMonitorControlSetInterfacePrimaryRank(IPMonitorControlRef control, 215 CFStringRef ifname_cf, 216 SCNetworkServicePrimaryRank rank) 217{ 218 if (control->assertions == NULL) { 219 if (rank == kSCNetworkServicePrimaryRankDefault) { 220 /* no assertions, no need to store rank */ 221 return; 222 } 223 control->assertions 224 = CFDictionaryCreateMutable(NULL, 0, 225 &kCFTypeDictionaryKeyCallBacks, 226 &kCFTypeDictionaryValueCallBacks); 227 } 228 if (rank == kSCNetworkServicePrimaryRankDefault) { 229 CFDictionaryRemoveValue(control->assertions, ifname_cf); 230 if (CFDictionaryGetCount(control->assertions) == 0) { 231 my_CFRelease(&control->assertions); 232 } 233 } 234 else { 235 CFNumberRef rank_cf; 236 237 rank_cf = CFNumberCreate(NULL, kCFNumberSInt32Type, &rank); 238 CFDictionarySetValue(control->assertions, ifname_cf, rank_cf); 239 CFRelease(rank_cf); 240 } 241 return; 242} 243 244STATIC void 245ApplyInterfaceRank(const void * key, const void * value, void * context) 246{ 247 xpc_connection_t connection = (xpc_connection_t)context; 248 char ifname[IF_NAMESIZE]; 249 SCNetworkServicePrimaryRank rank; 250 xpc_object_t request; 251 252 if (!CFStringGetCString(key, ifname, sizeof(ifname), 253 kCFStringEncodingUTF8)) { 254 return; 255 } 256 if (!CFNumberGetValue(value, kCFNumberSInt32Type, &rank)) { 257 return; 258 } 259 request = create_request_dictionary(); 260 xpc_dictionary_set_uint64(request, 261 kIPMonitorControlRequestKeyType, 262 kIPMonitorControlRequestTypeSetInterfaceRank); 263 xpc_dictionary_set_string(request, 264 kIPMonitorControlRequestKeyInterfaceName, 265 ifname); 266 xpc_dictionary_set_uint64(request, 267 kIPMonitorControlRequestKeyPrimaryRank, 268 rank); 269 xpc_connection_send_message(connection, request); 270 xpc_release(request); 271 return; 272} 273 274 275STATIC void 276_IPMonitorControlSetInterfaceAdvisory(IPMonitorControlRef control, 277 CFStringRef ifname_cf, 278 SCNetworkInterfaceAdvisory advisory) 279{ 280 if (control->advisories == NULL) { 281 if (advisory == kSCNetworkInterfaceAdvisoryNone) { 282 /* no advisories, no need to store advisory */ 283 return; 284 } 285 control->advisories 286 = CFDictionaryCreateMutable(NULL, 0, 287 &kCFTypeDictionaryKeyCallBacks, 288 &kCFTypeDictionaryValueCallBacks); 289 } 290 if (advisory == kSCNetworkInterfaceAdvisoryNone) { 291 CFDictionaryRemoveValue(control->advisories, ifname_cf); 292 if (CFDictionaryGetCount(control->advisories) == 0) { 293 my_CFRelease(&control->advisories); 294 } 295 } 296 else { 297 CFNumberRef advisory_cf; 298 299 advisory_cf = CFNumberCreate(NULL, kCFNumberSInt32Type, &advisory); 300 CFDictionarySetValue(control->advisories, ifname_cf, advisory_cf); 301 CFRelease(advisory_cf); 302 } 303 return; 304} 305 306STATIC void 307ApplyInterfaceAdvisory(const void * key, const void * value, void * context) 308{ 309 xpc_connection_t connection = (xpc_connection_t)context; 310 char ifname[IF_NAMESIZE]; 311 SCNetworkInterfaceAdvisory advisory; 312 xpc_object_t request; 313 314 if (!CFStringGetCString(key, ifname, sizeof(ifname), 315 kCFStringEncodingUTF8)) { 316 return; 317 } 318 if (!CFNumberGetValue(value, kCFNumberSInt32Type, &advisory)) { 319 return; 320 } 321 request = create_request_dictionary(); 322 xpc_dictionary_set_uint64(request, 323 kIPMonitorControlRequestKeyType, 324 kIPMonitorControlRequestTypeSetInterfaceAdvisory); 325 xpc_dictionary_set_string(request, 326 kIPMonitorControlRequestKeyInterfaceName, 327 ifname); 328 xpc_dictionary_set_uint64(request, 329 kIPMonitorControlRequestKeyAdvisory, 330 advisory); 331 xpc_connection_send_message(connection, request); 332 xpc_release(request); 333 return; 334} 335 336 337/** 338 ** IPMonitorControl SPI 339 **/ 340PRIVATE_EXTERN IPMonitorControlRef 341IPMonitorControlCreate(void) 342{ 343 xpc_connection_t connection; 344 IPMonitorControlRef control; 345 uint64_t flags = XPC_CONNECTION_MACH_SERVICE_PRIVILEGED; 346 xpc_handler_t handler; 347 dispatch_queue_t queue; 348 349 control = __IPMonitorControlAllocate(NULL); 350 queue = dispatch_queue_create("IPMonitorControl", NULL); 351 connection 352 = xpc_connection_create_mach_service(kIPMonitorControlServerName, 353 queue, flags); 354 handler = ^(xpc_object_t event) { 355 Boolean retry; 356 357 (void)IPMonitorControlHandleResponse(event, TRUE, &retry); 358 if (retry) { 359 if (control->assertions != NULL) { 360 CFDictionaryApplyFunction(control->assertions, 361 ApplyInterfaceRank, 362 control->connection); 363 } 364 if (control->advisories != NULL) { 365 CFDictionaryApplyFunction(control->advisories, 366 ApplyInterfaceAdvisory, 367 control->connection); 368 } 369 } 370 }; 371 xpc_connection_set_event_handler(connection, handler); 372 control->connection = connection; 373 control->queue = queue; 374 xpc_connection_resume(connection); 375 return (control); 376} 377 378STATIC xpc_object_t 379IPMonitorControlSendRequest(IPMonitorControlRef control, 380 xpc_object_t request) 381{ 382 xpc_object_t reply; 383 384 while (TRUE) { 385 Boolean retry_on_error = FALSE; 386 Boolean success; 387 388 reply = xpc_connection_send_message_with_reply_sync(control->connection, 389 request); 390 if (reply == NULL) { 391 my_log(LOG_NOTICE, "failed to send message"); 392 break; 393 } 394 success = IPMonitorControlHandleResponse(reply, FALSE, 395 &retry_on_error); 396 if (success) { 397 break; 398 } 399 xpc_release(reply); 400 reply = NULL; 401 if (retry_on_error) { 402 continue; 403 } 404 my_log(LOG_NOTICE, "fatal error"); 405 break; 406 } 407 return (reply); 408} 409 410PRIVATE_EXTERN Boolean 411IPMonitorControlSetInterfacePrimaryRank(IPMonitorControlRef control, 412 CFStringRef ifname_cf, 413 SCNetworkServicePrimaryRank rank) 414{ 415 char ifname[IF_NAMESIZE]; 416 xpc_object_t reply; 417 xpc_object_t request; 418 Boolean success = FALSE; 419 420 if (!CFStringGetCString(ifname_cf, ifname, sizeof(ifname), 421 kCFStringEncodingUTF8)) { 422 return (FALSE); 423 } 424 425 request = create_request_dictionary(); 426 xpc_dictionary_set_uint64(request, 427 kIPMonitorControlRequestKeyType, 428 kIPMonitorControlRequestTypeSetInterfaceRank); 429 xpc_dictionary_set_string(request, 430 kIPMonitorControlRequestKeyInterfaceName, 431 ifname); 432 xpc_dictionary_set_uint64(request, 433 kIPMonitorControlRequestKeyPrimaryRank, 434 rank); 435 reply = IPMonitorControlSendRequest(control, request); 436 xpc_release(request); 437 if (reply != NULL) { 438 success = TRUE; 439 xpc_release(reply); 440 441 /* sync our state */ 442 CFRetain(ifname_cf); 443 CFRetain(control); 444 dispatch_async(control->queue, 445 ^{ 446 _IPMonitorControlSetInterfacePrimaryRank(control, 447 ifname_cf, 448 rank); 449 CFRelease(ifname_cf); 450 CFRelease(control); 451 }); 452 } 453 return (success); 454} 455 456PRIVATE_EXTERN SCNetworkServicePrimaryRank 457IPMonitorControlGetInterfacePrimaryRank(IPMonitorControlRef control, 458 CFStringRef ifname_cf) 459{ 460 char ifname[IF_NAMESIZE]; 461 SCNetworkServicePrimaryRank rank; 462 xpc_object_t reply; 463 xpc_object_t request; 464 465 rank = kSCNetworkServicePrimaryRankDefault; 466 if (!CFStringGetCString(ifname_cf, ifname, sizeof(ifname), 467 kCFStringEncodingUTF8)) { 468 return rank; 469 } 470 471 request = create_request_dictionary(); 472 xpc_dictionary_set_uint64(request, 473 kIPMonitorControlRequestKeyType, 474 kIPMonitorControlRequestTypeGetInterfaceRank); 475 xpc_dictionary_set_string(request, 476 kIPMonitorControlRequestKeyInterfaceName, 477 ifname); 478 reply = IPMonitorControlSendRequest(control, request); 479 if (reply != NULL) { 480 rank = (SCNetworkServicePrimaryRank) 481 xpc_dictionary_get_uint64(reply, 482 kIPMonitorControlResponseKeyPrimaryRank); 483 xpc_release(reply); 484 } 485 xpc_release(request); 486 return (rank); 487} 488 489PRIVATE_EXTERN Boolean 490IPMonitorControlSetInterfaceAdvisory(IPMonitorControlRef control, 491 CFStringRef ifname_cf, 492 SCNetworkInterfaceAdvisory advisory, 493 CFStringRef reason) 494{ 495 char ifname[IF_NAMESIZE]; 496 char * reason_str = NULL; 497 xpc_object_t reply; 498 xpc_object_t request; 499 Boolean success = FALSE; 500 501 if (!CFStringGetCString(ifname_cf, ifname, sizeof(ifname), 502 kCFStringEncodingUTF8)) { 503 return (FALSE); 504 } 505 if (reason != NULL) { 506 reason_str 507 = _SC_cfstring_to_cstring(reason, NULL, 0, kCFStringEncodingUTF8); 508 } 509 request = create_request_dictionary(); 510 xpc_dictionary_set_uint64(request, 511 kIPMonitorControlRequestKeyType, 512 kIPMonitorControlRequestTypeSetInterfaceAdvisory); 513 xpc_dictionary_set_string(request, 514 kIPMonitorControlRequestKeyInterfaceName, 515 ifname); 516 xpc_dictionary_set_uint64(request, 517 kIPMonitorControlRequestKeyAdvisory, 518 advisory); 519 if (reason_str != NULL) { 520 xpc_dictionary_set_string(request, 521 kIPMonitorControlRequestKeyReason, 522 reason_str); 523 CFAllocatorDeallocate(NULL, reason_str); 524 } 525 reply = IPMonitorControlSendRequest(control, request); 526 xpc_release(request); 527 if (reply != NULL) { 528 xpc_release(reply); 529 success = TRUE; 530 531 /* sync our state */ 532 CFRetain(ifname_cf); 533 CFRetain(control); 534 dispatch_async(control->queue, 535 ^{ 536 _IPMonitorControlSetInterfaceAdvisory(control, 537 ifname_cf, 538 advisory); 539 CFRelease(ifname_cf); 540 CFRelease(control); 541 }); 542 } 543 return (success); 544} 545 546PRIVATE_EXTERN Boolean 547IPMonitorControlInterfaceAdvisoryIsSet(IPMonitorControlRef control, 548 CFStringRef ifname_cf) 549{ 550 char ifname[IF_NAMESIZE]; 551 xpc_object_t reply; 552 xpc_object_t request; 553 Boolean is_set = FALSE; 554 555 if (!CFStringGetCString(ifname_cf, ifname, sizeof(ifname), 556 kCFStringEncodingUTF8)) { 557 return (FALSE); 558 } 559 request = create_request_dictionary(); 560 xpc_dictionary_set_uint64(request, 561 kIPMonitorControlRequestKeyType, 562 kIPMonitorControlRequestTypeInterfaceAdvisoryIsSet); 563 xpc_dictionary_set_string(request, 564 kIPMonitorControlRequestKeyInterfaceName, 565 ifname); 566 reply = IPMonitorControlSendRequest(control, request); 567 xpc_release(request); 568 if (reply != NULL) { 569 if (xpc_dictionary_get_bool(reply, 570 kIPMonitorControlResponseKeyAdvisoryIsSet)) { 571 is_set = TRUE; 572 } 573 xpc_release(reply); 574 } 575 return (is_set); 576} 577 578PRIVATE_EXTERN Boolean 579IPMonitorControlAnyInterfaceAdvisoryIsSet(IPMonitorControlRef control) 580{ 581 xpc_object_t reply; 582 xpc_object_t request; 583 Boolean is_set = FALSE; 584 585 request = create_request_dictionary(); 586 xpc_dictionary_set_uint64(request, 587 kIPMonitorControlRequestKeyType, 588 kIPMonitorControlRequestTypeAnyInterfaceAdvisoryIsSet); 589 reply = IPMonitorControlSendRequest(control, request); 590 xpc_release(request); 591 if (reply != NULL) { 592 if (xpc_dictionary_get_bool(reply, 593 kIPMonitorControlResponseKeyAdvisoryIsSet)) { 594 is_set = TRUE; 595 } 596 xpc_release(reply); 597 } 598 return (is_set); 599} 600 601PRIVATE_EXTERN CFStringRef 602IPMonitorControlCopyInterfaceAdvisoryNotificationKey(CFStringRef ifname) 603{ 604 return (_IPMonitorControlCopyInterfaceAdvisoryNotificationKey(ifname)); 605}