this repo has no description
at fixPythonPipStalling 687 lines 16 kB view raw
1/* 2 * Copyright (c) 2002-2019 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 * August 5, 2002 Allan Nathanson <ajn@apple.com> 28 * - split code out from eventmon.c 29 */ 30 31#include "eventmon.h" 32#include "ev_dlil.h" 33#include "ev_extra.h" 34 35static CFStringRef 36create_interface_cfstring(const char * if_name) 37{ 38 CFStringRef interface; 39 40 interface = CFStringCreateWithCString(NULL, if_name, 41 kCFStringEncodingUTF8); 42 return (interface); 43} 44 45static CFStringRef 46create_interface_key(CFStringRef interface) 47{ 48 CFStringRef key; 49 50 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 51 kSCDynamicStoreDomainState, 52 interface, 53 kSCEntNetLink); 54 return (key); 55} 56 57 58static CFMutableDictionaryRef 59copy_mutable_dictionary(CFDictionaryRef dict) 60{ 61 CFMutableDictionaryRef newDict; 62 63 if (isA_CFDictionary(dict) != NULL) { 64 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); 65 } 66 else { 67 newDict = CFDictionaryCreateMutable(NULL, 68 0, 69 &kCFTypeDictionaryKeyCallBacks, 70 &kCFTypeDictionaryValueCallBacks); 71 } 72 return (newDict); 73} 74 75static CFMutableDictionaryRef 76copy_entity(CFStringRef key) 77{ 78 CFDictionaryRef dict; 79 CFMutableDictionaryRef newDict = NULL; 80 81 dict = SCDynamicStoreCopyValue(store, key); 82 newDict = copy_mutable_dictionary(dict); 83 if (dict != NULL) { 84 CFRelease(dict); 85 } 86 return (newDict); 87} 88 89 90static void 91interface_update_status(const char *if_name, 92 CFStringRef interface, 93 CFBooleanRef active, boolean_t attach, 94 CFBooleanRef expensive, boolean_t only_if_different) 95{ 96 CFStringRef key = NULL; 97 CFMutableDictionaryRef newDict; 98 CFDictionaryRef oldDict; 99 100 key = create_interface_key(interface); 101 oldDict = SCDynamicStoreCopyValue(store, key); 102 if (oldDict != NULL && isA_CFDictionary(oldDict) == NULL) { 103 CFRelease(oldDict); 104 oldDict = NULL; 105 } 106 newDict = copy_mutable_dictionary(oldDict); 107 108 /* if new status available, update cache */ 109 if (active != NULL) { 110 CFDictionarySetValue(newDict, kSCPropNetLinkActive, active); 111 } else { 112 CFDictionaryRemoveValue(newDict, kSCPropNetLinkActive); 113 } 114 115 if (attach) { 116 /* the interface was attached, remove stale state */ 117 CFDictionaryRemoveValue(newDict, kSCPropNetLinkDetaching); 118 } 119 120 if ((expensive != NULL) && CFBooleanGetValue(expensive)) { 121 CFDictionarySetValue(newDict, kSCPropNetLinkExpensive, expensive); 122 } else { 123 CFDictionaryRemoveValue(newDict, kSCPropNetLinkExpensive); 124 } 125 126 /* update the SCDynamicStore */ 127 if (CFDictionaryGetCount(newDict) > 0) { 128 /* set the value */ 129 if (!only_if_different 130 || oldDict == NULL 131 || !CFEqual(oldDict, newDict)) { 132 SC_log(LOG_DEBUG, "Update interface link status: %s: %@", if_name, newDict); 133 SCDynamicStoreSetValue(store, key, newDict); 134 } 135 } else { 136 /* remove the value */ 137 if (oldDict != NULL) { 138 SC_log(LOG_DEBUG, "Update interface link status: %s: <removed>", if_name); 139 } 140 SCDynamicStoreRemoveValue(store, key); 141 } 142 143 CFRelease(key); 144 CFRelease(newDict); 145 if (oldDict != NULL) { 146 CFRelease(oldDict); 147 } 148 return; 149} 150 151 152#ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED 153static CFStringRef 154create_linkquality_key(CFStringRef interface) 155{ 156 CFStringRef key; 157 158 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 159 kSCDynamicStoreDomainState, 160 interface, 161 kSCEntNetLinkQuality); 162 return (key); 163} 164 165 166__private_extern__ 167void 168interface_update_quality_metric(const char *if_name, 169 int quality) 170{ 171 CFStringRef key; 172 CFStringRef interface; 173 CFMutableDictionaryRef newDict; 174 175 interface = create_interface_cfstring(if_name); 176 key = create_linkquality_key(interface); 177 newDict = copy_entity(key); 178 179 if (quality != IFNET_LQM_THRESH_UNKNOWN) { 180 CFNumberRef linkquality; 181 182 linkquality = CFNumberCreate(NULL, kCFNumberIntType, &quality); 183 CFDictionarySetValue(newDict, kSCPropNetLinkQuality, linkquality); 184 CFRelease(linkquality); 185 } else { 186 CFDictionaryRemoveValue(newDict, kSCPropNetLinkQuality); 187 } 188 189 /* update status */ 190 if (CFDictionaryGetCount(newDict) > 0) { 191 SC_log(LOG_DEBUG, "Update interface link quality: %s: %@", if_name, newDict); 192 SCDynamicStoreSetValue(store, key, newDict); 193 } else { 194 SC_log(LOG_DEBUG, "Update interface link quality: %s: <unknown>", if_name); 195 SCDynamicStoreRemoveValue(store, key); 196 } 197 198 CFRelease(interface); 199 CFRelease(key); 200 CFRelease(newDict); 201 return; 202} 203 204 205static 206void 207link_update_quality_metric(const char *if_name) 208{ 209 struct ifreq ifr; 210 int quality = IFNET_LQM_THRESH_UNKNOWN; 211 int sock; 212 213 sock = dgram_socket(AF_INET); 214 if (sock == -1) { 215 goto done; 216 } 217 218 memset((char *)&ifr, 0, sizeof(ifr)); 219 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", if_name); 220 221 if (ioctl(sock, SIOCGIFLINKQUALITYMETRIC, (caddr_t)&ifr) != -1) { 222 quality = ifr.ifr_link_quality_metric; 223 } 224 225 done: 226 227 interface_update_quality_metric(if_name, quality); 228 229 if (sock != -1) { 230 close(sock); 231 } 232 return; 233 234} 235#endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */ 236 237 238#ifdef KEV_DL_ISSUES 239static CFStringRef 240create_link_issues_key(CFStringRef interface) 241{ 242 CFStringRef key; 243 244 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 245 kSCDynamicStoreDomainState, 246 interface, 247 kSCEntNetLinkIssues); 248 return (key); 249} 250 251 252__private_extern__ 253void 254interface_update_link_issues(const char *if_name, 255 uint64_t timestamp, 256 uint8_t *modid, 257 size_t modid_size, 258 uint8_t *info, 259 size_t info_size) 260{ 261 CFDataRef infoData; 262 CFStringRef interface; 263 CFStringRef key; 264 CFDataRef modidData; 265 CFMutableDictionaryRef newDict; 266 CFDateRef timeStamp; 267 268 interface = create_interface_cfstring(if_name); 269 key = create_link_issues_key(interface); 270 271 newDict = copy_entity(key); 272 273 modidData = CFDataCreate(NULL, modid, modid_size); 274 CFDictionarySetValue(newDict, kSCPropNetLinkIssuesModuleID, modidData); 275 CFRelease(modidData); 276 277 if (info_size != 0) { 278 infoData = CFDataCreate(NULL, info, info_size); 279 CFDictionarySetValue(newDict, kSCPropNetLinkIssuesInfo, infoData); 280 CFRelease(infoData); 281 } else { 282 CFDictionaryRemoveValue(newDict, kSCPropNetLinkIssuesInfo); 283 } 284 285 timeStamp = CFDateCreate(NULL, timestamp); 286 CFDictionarySetValue(newDict, kSCPropNetLinkIssuesTimeStamp, timeStamp); 287 CFRelease(timeStamp); 288 289 SC_log(LOG_DEBUG, "Update interface link issues: %s: %@", if_name, newDict); 290 SCDynamicStoreSetValue(store, key, newDict); 291 CFRelease(interface); 292 CFRelease(newDict); 293 CFRelease(key); 294 return; 295} 296#endif /* KEV_DL_ISSUES */ 297 298 299__private_extern__ 300void 301interface_detaching(const char *if_name) 302{ 303 CFStringRef interface; 304 CFStringRef key; 305 CFMutableDictionaryRef newDict; 306 307 SC_log(LOG_DEBUG, "Detach interface: %s", if_name); 308 309 interface = create_interface_cfstring(if_name); 310 key = create_interface_key(interface); 311 newDict = copy_entity(key); 312 CFDictionarySetValue(newDict, kSCPropNetLinkDetaching, 313 kCFBooleanTrue); 314 SCDynamicStoreSetValue(store, key, newDict); 315 CFRelease(interface); 316 CFRelease(newDict); 317 CFRelease(key); 318 return; 319} 320 321static CFStringRef 322create_nat64_key(CFStringRef interface) 323{ 324 CFStringRef key; 325 326 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 327 kSCDynamicStoreDomainState, 328 interface, 329 kSCEntNetNAT64); 330 return (key); 331} 332 333 334static void 335interface_remove(const char *if_name) 336{ 337 CFStringRef interface; 338 CFStringRef key; 339 340 SC_log(LOG_DEBUG, "Remove interface: %s", if_name); 341 342 interface = create_interface_cfstring(if_name); 343 344 key = create_interface_key(interface); 345 SCDynamicStoreRemoveValue(store, key); 346 CFRelease(key); 347 348 key = create_nat64_key(interface); 349 SCDynamicStoreRemoveValue(store, key); 350 CFRelease(key); 351 352#ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED 353 key = create_linkquality_key(interface); 354 SCDynamicStoreRemoveValue(store, key); 355 CFRelease(key); 356#endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */ 357 358#ifdef KEV_DL_ISSUES 359 key = create_link_issues_key(interface); 360 SCDynamicStoreRemoveValue(store, key); 361 CFRelease(key); 362#endif /* KEV_DL_ISSUES */ 363 364 CFRelease(interface); 365 return; 366} 367 368 369static void 370S_link_update_status(const char *if_name, CFStringRef interface, boolean_t attach, boolean_t only_if_different) 371{ 372 CFBooleanRef active = NULL; 373 CFBooleanRef expensive = NULL; 374 struct ifmediareq ifm; 375 int sock; 376 377 sock = dgram_socket(AF_INET); 378 if (sock == -1) { 379 return; 380 } 381 382 /* get "Link" */ 383 memset((char *)&ifm, 0, sizeof(ifm)); 384 (void) strlcpy(ifm.ifm_name, if_name, sizeof(ifm.ifm_name)); 385 386 if (ioctl(sock, SIOCGIFXMEDIA, (caddr_t)&ifm) == -1) { 387 /* if media status not available for this interface */ 388 goto update; 389 } 390 391 if (ifm.ifm_count == 0) { 392 /* no media types */ 393 goto update; 394 } 395 396 if (!(ifm.ifm_status & IFM_AVALID)) { 397 /* if active bit not valid */ 398 goto update; 399 } 400 401 if (ifm.ifm_status & IFM_ACTIVE) { 402 active = kCFBooleanTrue; 403 } else { 404 active = kCFBooleanFalse; 405 } 406 407 update: 408 409 if ((active == NULL) || CFBooleanGetValue(active)) { 410 /* 411 * if link status not available or active (link UP), 412 * set "Expensive" 413 */ 414 expensive = interface_update_expensive(if_name); 415 } 416 417 /* update status */ 418 interface_update_status(if_name, interface, active, attach, expensive, only_if_different); 419 close(sock); 420 return; 421} 422 423__private_extern__ 424void 425link_update_status(const char *if_name, boolean_t attach, boolean_t only_if_different) 426{ 427 CFStringRef interface; 428 429 interface = create_interface_cfstring(if_name); 430 S_link_update_status(if_name, interface, attach, only_if_different); 431 CFRelease(interface); 432} 433 434 435__private_extern__ 436void 437link_update_status_if_missing(const char * if_name) 438{ 439 CFStringRef interface; 440 CFStringRef key; 441 CFDictionaryRef dict; 442 443 interface = create_interface_cfstring(if_name); 444 key = create_interface_key(interface); 445 dict = SCDynamicStoreCopyValue(store, key); 446 if (dict != NULL) { 447 /* it's already present, don't update */ 448 CFRelease(dict); 449 goto done; 450 } 451 S_link_update_status(if_name, interface, FALSE, FALSE); 452 dict = SCDynamicStoreCopyValue(store, key); 453 if (dict != NULL) { 454 /* our action made it appear */ 455 messages_add_msg_with_arg("added missing link status", if_name); 456 CFRelease(dict); 457 } 458 done: 459 CFRelease(interface); 460 CFRelease(key); 461 return; 462} 463 464__private_extern__ 465CFMutableArrayRef 466interfaceListCopy(void) 467{ 468 CFStringRef cacheKey; 469 CFDictionaryRef dict; 470 CFMutableArrayRef ret_ifList = NULL; 471 472 cacheKey = SCDynamicStoreKeyCreateNetworkInterface(NULL, 473 kSCDynamicStoreDomainState); 474 dict = SCDynamicStoreCopyValue(store, cacheKey); 475 CFRelease(cacheKey); 476 if (dict != NULL) { 477 if (isA_CFDictionary(dict) != NULL) { 478 CFArrayRef ifList; 479 480 ifList = CFDictionaryGetValue(dict, kSCPropNetInterfaces); 481 if (isA_CFArray(ifList) != NULL) { 482 ret_ifList = CFArrayCreateMutableCopy(NULL, 0, ifList); 483 } 484 } 485 CFRelease(dict); 486 } 487 if (ret_ifList == NULL) { 488 ret_ifList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 489 } 490 return (ret_ifList); 491} 492 493 494__private_extern__ 495void 496interfaceListUpdate(CFArrayRef ifList) 497{ 498 CFStringRef cacheKey; 499 CFDictionaryRef dict; 500 501 cacheKey = SCDynamicStoreKeyCreateNetworkInterface(NULL, 502 kSCDynamicStoreDomainState); 503 dict = SCDynamicStoreCopyValue(store, cacheKey); 504 if (dict != NULL && isA_CFDictionary(dict) == NULL) { 505 CFRelease(dict); 506 dict = NULL; 507 } 508 if (dict == NULL) { 509 dict = CFDictionaryCreate(NULL, 510 (const void * *)&kSCPropNetInterfaces, 511 (const void * *)&ifList, 512 1, 513 &kCFTypeDictionaryKeyCallBacks, 514 &kCFTypeDictionaryValueCallBacks); 515 SCDynamicStoreSetValue(store, cacheKey, dict); 516 CFRelease(dict); 517 518 } 519 else { 520 CFMutableDictionaryRef newDict; 521 522 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); 523 CFRelease(dict); 524 CFDictionarySetValue(newDict, kSCPropNetInterfaces, ifList); 525 SCDynamicStoreSetValue(store, cacheKey, newDict); 526 CFRelease(newDict); 527 } 528 CFRelease(cacheKey); 529 return; 530} 531 532 533__private_extern__ 534Boolean 535interfaceListAddInterface(CFMutableArrayRef ifList, const char * if_name) 536{ 537 Boolean added = FALSE; 538 CFStringRef interface; 539 540 interface = create_interface_cfstring(if_name); 541 if (!CFArrayContainsValue(ifList, 542 CFRangeMake(0, CFArrayGetCount(ifList)), 543 interface)) { 544 /* interface was added, prime the link-specific values */ 545 added = TRUE; 546 CFArrayAppendValue(ifList, interface); 547 link_update_status(if_name, TRUE, FALSE); 548#ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED 549 link_update_quality_metric(if_name); 550#endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */ 551 } 552 else { 553 /* only update the link status if it is different */ 554 link_update_status(if_name, FALSE, TRUE); 555 } 556 CFRelease(interface); 557 return (added); 558} 559 560 561static Boolean 562interfaceListRemoveInterface(CFMutableArrayRef ifList, const char * if_name) 563{ 564 CFStringRef interface; 565 CFIndex where; 566 567 interface = create_interface_cfstring(if_name); 568 where = CFArrayGetFirstIndexOfValue(ifList, 569 CFRangeMake(0, CFArrayGetCount(ifList)), 570 interface); 571 CFRelease(interface); 572 if (where != kCFNotFound) { 573 CFArrayRemoveValueAtIndex(ifList, where); 574 interface_remove(if_name); 575 } 576 return (where != kCFNotFound); 577} 578 579 580__private_extern__ 581void 582link_add(const char *if_name) 583{ 584 CFMutableArrayRef ifList; 585 586 ifList = interfaceListCopy(); 587 if (interfaceListAddInterface(ifList, if_name)) { 588 /* interface was added, update the global list */ 589 messages_add_msg_with_arg("link_add", if_name); 590 interfaceListUpdate(ifList); 591 config_new_interface(if_name); 592 } 593 CFRelease(ifList); 594 return; 595} 596 597 598__private_extern__ 599void 600link_remove(const char *if_name) 601{ 602 CFMutableArrayRef ifList; 603 604 ifList = interfaceListCopy(); 605 if (interfaceListRemoveInterface(ifList, if_name)) { 606 /* interface was removed, update the global list */ 607 interfaceListUpdate(ifList); 608 } 609 CFRelease(ifList); 610 return; 611} 612 613 614__private_extern__ 615void 616interface_update_delegation(const char *if_name) 617{ 618 CFStringRef interface; 619 CFStringRef key; 620 621 interface = create_interface_cfstring(if_name); 622 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 623 kSCDynamicStoreDomainState, 624 interface, 625 kSCEntNetInterfaceDelegation); 626 SC_log(LOG_DEBUG, "Post interface delegation change: %s", if_name); 627 SCDynamicStoreNotifyValue(store, key); 628 CFRelease(key); 629 CFRelease(interface); 630 return; 631} 632 633 634#ifdef KEV_DL_IF_IDLE_ROUTE_REFCNT 635#define INVALID_SOCKET_REF -1 636static 637int 638socket_reference_count(const char* if_name) { 639 struct ifreq ifr; 640 int ref = INVALID_SOCKET_REF; 641 int s; 642 643 s = dgram_socket(AF_INET); 644 if (s == -1) { 645 return (ref); 646 } 647 648 memset((char *)&ifr, 0, sizeof(ifr)); 649 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", if_name); 650 651 if (ioctl(s, SIOCGIFGETRTREFCNT, (caddr_t)&ifr) != -1) { 652 ref = ifr.ifr_route_refcnt; 653 } else { 654 ref = INVALID_SOCKET_REF; 655 } 656 close(s); 657 return (ref); 658} 659 660 661__private_extern__ 662void 663interface_update_idle_state(const char *if_name) 664{ 665 CFStringRef interface; 666 CFStringRef key; 667 int ref; 668 669 /* only update the SCDynamicStore if the idle ref count is still 0 */ 670 ref = socket_reference_count(if_name); 671 if (ref != 0) { 672 return; 673 } 674 675 interface = create_interface_cfstring(if_name); 676 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 677 kSCDynamicStoreDomainState, 678 interface, 679 kSCEntNetIdleRoute); 680 681 SC_log(LOG_DEBUG, "Post interface idle: %s", if_name); 682 SCDynamicStoreNotifyValue(store, key); 683 CFRelease(key); 684 CFRelease(interface); 685 return; 686} 687#endif // KEV_DL_IF_IDLE_ROUTE_REFCNT