this repo has no description
at fixPythonPipStalling 862 lines 24 kB view raw
1/* 2 * Copyright (c) 2000-2006, 2008-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 * June 1, 2001 Allan Nathanson <ajn@apple.com> 28 * - public API conversion 29 * 30 * March 24, 2000 Allan Nathanson <ajn@apple.com> 31 * - initial revision 32 */ 33 34#include <TargetConditionals.h> 35#include <stdlib.h> 36#include <unistd.h> 37#include <sys/types.h> 38#include <mach/mach.h> 39#include <mach/mach_error.h> 40#include <servers/bootstrap.h> 41#include <bootstrap_priv.h> 42 43#include "SCDynamicStoreInternal.h" 44#include "config.h" /* MiG generated file */ 45#include "SCD.h" 46 47static CFStringRef _sc_bundleID = NULL; 48static pthread_mutex_t _sc_lock = PTHREAD_MUTEX_INITIALIZER; 49static mach_port_t _sc_server = MACH_PORT_NULL; 50static unsigned int _sc_store_cnt = 0; 51static unsigned int _sc_store_max = 50; /* complain if SCDynamicStore objects exceeds this [soft-]limit */ 52 53 54static const char *notifyType[] = { 55 "", 56 "wait", 57 "inform w/callback", 58 "inform w/mach port", 59 "inform w/fd", 60 "inform w/runLoop", 61 "inform w/dispatch" 62}; 63 64 65void 66_SCDynamicStoreSetSessionWatchLimit(unsigned int limit) 67{ 68 _sc_store_max = limit; 69 return; 70} 71 72 73__private_extern__ os_log_t 74__log_SCDynamicStore(void) 75{ 76 static os_log_t log = NULL; 77 78 if (log == NULL) { 79 log = os_log_create("com.apple.SystemConfiguration", "SCDynamicStore"); 80 } 81 82 return log; 83} 84 85 86static CFStringRef 87__SCDynamicStoreCopyDescription(CFTypeRef cf) { 88 CFAllocatorRef allocator = CFGetAllocator(cf); 89 CFMutableStringRef result; 90 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)cf; 91 92 result = CFStringCreateMutable(allocator, 0); 93 CFStringAppendFormat(result, NULL, CFSTR("<SCDynamicStore %p [%p]> {"), cf, allocator); 94 if (storePrivate->server != MACH_PORT_NULL) { 95 CFStringAppendFormat(result, NULL, CFSTR("server port = 0x%x"), storePrivate->server); 96 } else { 97 CFStringAppendFormat(result, NULL, CFSTR("server not (no longer) available")); 98 } 99 if (storePrivate->disconnectFunction != NULL) { 100 CFStringAppendFormat(result, NULL, CFSTR(", disconnect = %p"), storePrivate->disconnectFunction); 101 } 102 switch (storePrivate->notifyStatus) { 103 case Using_NotifierWait : 104 CFStringAppendFormat(result, NULL, CFSTR(", waiting for a notification")); 105 break; 106 case Using_NotifierInformViaMachPort : 107 CFStringAppendFormat(result, NULL, CFSTR(", mach port notifications")); 108 break; 109 case Using_NotifierInformViaFD : 110 CFStringAppendFormat(result, NULL, CFSTR(", FD notifications")); 111 break; 112 case Using_NotifierInformViaRunLoop : 113 case Using_NotifierInformViaDispatch : 114 if (storePrivate->notifyStatus == Using_NotifierInformViaRunLoop) { 115 CFStringAppendFormat(result, NULL, CFSTR(", runloop notifications")); 116 CFStringAppendFormat(result, NULL, CFSTR(" {callout = %p"), storePrivate->rlsFunction); 117 CFStringAppendFormat(result, NULL, CFSTR(", info = %p"), storePrivate->rlsContext.info); 118 CFStringAppendFormat(result, NULL, CFSTR(", rls = %p"), storePrivate->rls); 119 CFStringAppendFormat(result, NULL, CFSTR(", notify rls = %@" ), storePrivate->rlsNotifyRLS); 120 } else if (storePrivate->notifyStatus == Using_NotifierInformViaDispatch) { 121 CFStringAppendFormat(result, NULL, CFSTR(", dispatch notifications")); 122 CFStringAppendFormat(result, NULL, CFSTR(" {callout = %p"), storePrivate->rlsFunction); 123 CFStringAppendFormat(result, NULL, CFSTR(", info = %p"), storePrivate->rlsContext.info); 124 CFStringAppendFormat(result, NULL, CFSTR(", queue = %p"), storePrivate->dispatchQueue); 125 CFStringAppendFormat(result, NULL, CFSTR(", source = %p"), storePrivate->dispatchSource); 126 } 127 CFStringAppendFormat(result, NULL, CFSTR("}")); 128 break; 129 default : 130 CFStringAppendFormat(result, NULL, CFSTR(", notification delivery not requested%s"), 131 storePrivate->rlsFunction ? " (yet)" : ""); 132 break; 133 } 134 CFStringAppendFormat(result, NULL, CFSTR("}")); 135 136 return result; 137} 138 139 140static void 141__SCDynamicStoreDeallocate(CFTypeRef cf) 142{ 143 int oldThreadState; 144 SCDynamicStoreRef store = (SCDynamicStoreRef)cf; 145 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; 146 147 (void) pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldThreadState); 148 149 /* Remove/cancel any outstanding notification requests. */ 150 (void) SCDynamicStoreNotifyCancel(store); 151 152 if (storePrivate->server != MACH_PORT_NULL) { 153 /* 154 * Remove our send right to the SCDynamicStore server. 155 * 156 * In the case of a "real" session this will result in our 157 * session being closed. 158 * 159 * In the case of a "NULL" session, we just remove the 160 * the send right reference we are holding. 161 */ 162 __MACH_PORT_DEBUG(TRUE, "*** __SCDynamicStoreDeallocate", storePrivate->server); 163 (void) mach_port_deallocate(mach_task_self(), storePrivate->server); 164 storePrivate->server = MACH_PORT_NULL; 165 } 166 167 (void) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldThreadState); 168 pthread_testcancel(); 169 170 /* release any callback context info */ 171 if (storePrivate->rlsContext.release != NULL) { 172 (*storePrivate->rlsContext.release)(storePrivate->rlsContext.info); 173 } 174 175 /* release any keys being watched */ 176 if (storePrivate->keys != NULL) CFRelease(storePrivate->keys); 177 if (storePrivate->patterns != NULL) CFRelease(storePrivate->patterns); 178 179 /* release any client info */ 180 if (storePrivate->name != NULL) CFRelease(storePrivate->name); 181 if (storePrivate->options != NULL) CFRelease(storePrivate->options); 182 183 /* release any cached content */ 184 if (storePrivate->cache_active) { 185 _SCDynamicStoreCacheClose(store); 186 } 187 188 _SC_ATOMIC_DEC(&_sc_store_cnt); 189 190 return; 191} 192 193 194static CFTypeID __kSCDynamicStoreTypeID = _kCFRuntimeNotATypeID; 195 196 197static const CFRuntimeClass __SCDynamicStoreClass = { 198 0, // version 199 "SCDynamicStore", // className 200 NULL, // init 201 NULL, // copy 202 __SCDynamicStoreDeallocate, // dealloc 203 NULL, // equal 204 NULL, // hash 205 NULL, // copyFormattingDesc 206 __SCDynamicStoreCopyDescription // copyDebugDesc 207}; 208 209 210static void 211childForkHandler() 212{ 213 /* the process has forked (and we are the child process) */ 214 215 _sc_server = MACH_PORT_NULL; 216 return; 217} 218 219 220static pthread_once_t initialized = PTHREAD_ONCE_INIT; 221 222static void 223__SCDynamicStoreInitialize(void) 224{ 225 CFBundleRef bundle; 226 227 /* register with CoreFoundation */ 228 __kSCDynamicStoreTypeID = _CFRuntimeRegisterClass(&__SCDynamicStoreClass); 229 230 /* add handler to cleanup after fork() */ 231 (void) pthread_atfork(NULL, NULL, childForkHandler); 232 233 /* get the application/executable/bundle name */ 234 bundle = CFBundleGetMainBundle(); 235 if (bundle != NULL) { 236 _sc_bundleID = CFBundleGetIdentifier(bundle); 237 if (_sc_bundleID != NULL) { 238 CFRetain(_sc_bundleID); 239 } else { 240 CFURLRef url; 241 242 url = CFBundleCopyExecutableURL(bundle); 243 if (url != NULL) { 244 _sc_bundleID = CFURLCopyPath(url); 245 CFRelease(url); 246 } 247 } 248 249 if (_sc_bundleID != NULL) { 250 if (CFEqual(_sc_bundleID, CFSTR("/"))) { 251 CFRelease(_sc_bundleID); 252 _sc_bundleID = CFStringCreateWithFormat(NULL, NULL, CFSTR("(%d)"), getpid()); 253 } 254 } 255 } 256 257 return; 258} 259 260 261static mach_port_t 262__SCDynamicStoreServerPort(SCDynamicStorePrivateRef storePrivate, kern_return_t *status) 263{ 264#pragma unused(storePrivate) 265 mach_port_t server = MACH_PORT_NULL; 266 char *server_name; 267 268 server_name = getenv("SCD_SERVER"); 269 270#ifndef DEBUG 271 /* 272 * only allow the SCDynamicStore server bootstrap name to be changed with 273 * DEBUG builds. For RELEASE builds, assume that no server is available. 274 */ 275 if (server_name != NULL) { 276 *status = BOOTSTRAP_UNKNOWN_SERVICE; 277 return MACH_PORT_NULL; 278 } 279#endif /* DEBUG */ 280 281 282 if (server_name == NULL) { 283 server_name = SCD_SERVER; 284 } 285 286#if defined(BOOTSTRAP_PRIVILEGED_SERVER) && !TARGET_OS_SIMULATOR 287 *status = bootstrap_look_up2(bootstrap_port, 288 server_name, 289 &server, 290 0, 291 BOOTSTRAP_PRIVILEGED_SERVER); 292#else // defined(BOOTSTRAP_PRIVILEGED_SERVER) && !TARGET_OS_SIMULATOR 293 *status = bootstrap_look_up(bootstrap_port, server_name, &server); 294#endif // defined(BOOTSTRAP_PRIVILEGED_SERVER) && !TARGET_OS_SIMULATOR 295 296 switch (*status) { 297 case BOOTSTRAP_SUCCESS : 298 /* service currently registered, "a good thing" (tm) */ 299 return server; 300 case BOOTSTRAP_NOT_PRIVILEGED : 301 /* the service is not privileged */ 302 break; 303 case BOOTSTRAP_UNKNOWN_SERVICE : 304 /* service not currently registered, try again later */ 305 break; 306 default : 307#ifdef DEBUG 308 SC_log(LOG_INFO, "bootstrap_look_up() failed: status=%s (%d)", 309 bootstrap_strerror(*status), 310 *status); 311#endif /* DEBUG */ 312 break; 313 } 314 315 return MACH_PORT_NULL; 316} 317 318 319SCDynamicStorePrivateRef 320__SCDynamicStoreCreatePrivate(CFAllocatorRef allocator, 321 const CFStringRef name, 322 SCDynamicStoreCallBack callout, 323 SCDynamicStoreContext *context) 324{ 325 unsigned int n; 326 uint32_t size; 327 SCDynamicStorePrivateRef storePrivate; 328 329 /* initialize runtime */ 330 pthread_once(&initialized, __SCDynamicStoreInitialize); 331 332 /* allocate session */ 333 size = sizeof(SCDynamicStorePrivate) - sizeof(CFRuntimeBase); 334 storePrivate = (SCDynamicStorePrivateRef)_CFRuntimeCreateInstance(allocator, 335 __kSCDynamicStoreTypeID, 336 size, 337 NULL); 338 if (storePrivate == NULL) { 339 _SCErrorSet(kSCStatusFailed); 340 return NULL; 341 } 342 343 /* initialize non-zero/NULL members */ 344 345 /* client side of the "configd" session */ 346 storePrivate->name = (name != NULL) ? CFRetain(name) : NULL; 347 348 /* Notification status */ 349 storePrivate->notifyStatus = NotifierNotRegistered; 350 351 /* "client" information associated with SCDynamicStoreCreateRunLoopSource() */ 352 storePrivate->rlsFunction = callout; 353 if (context != NULL) { 354 memcpy(&storePrivate->rlsContext, context, sizeof(SCDynamicStoreContext)); 355 if (context->retain != NULL) { 356 storePrivate->rlsContext.info = (void *)(*context->retain)(context->info); 357 } 358 } 359 360 /* "server" information associated with SCDynamicStoreNotifyFileDescriptor(); */ 361 storePrivate->notifyFile = -1; 362 363 /* watch for excessive SCDynamicStore usage */ 364 n = _SC_ATOMIC_INC(&_sc_store_cnt); 365 if (n > _sc_store_max) { 366 if (_sc_store_max > 0) { 367 SC_log(LOG_ERR, "SCDynamicStoreCreate(): number of SCDynamicStore objects now exceeds %u", n - 1); 368 _sc_store_max = (_sc_store_max < 5000) ? (_sc_store_max * 2) : 0; 369 _SC_crash_once("Excessive number of SCDynamicStore objects", NULL, NULL); 370 } 371 } 372 373 return storePrivate; 374} 375 376 377static void 378updateServerPort(SCDynamicStorePrivateRef storePrivate, mach_port_t *server, int *sc_status_p) 379{ 380 mach_port_t old_port; 381 382 pthread_mutex_lock(&_sc_lock); 383 old_port = _sc_server; 384 if (_sc_server != MACH_PORT_NULL) { 385 if (*server == _sc_server) { 386 // if the server we tried returned the error, save the old port, 387 // [re-]lookup the name to the server, and deallocate the original 388 // send [or dead name] right 389 _sc_server = __SCDynamicStoreServerPort(storePrivate, sc_status_p); 390 (void)mach_port_deallocate(mach_task_self(), old_port); 391 } else { 392 // another thread has refreshed the [main] SCDynamicStore server port 393 } 394 } else { 395 _sc_server = __SCDynamicStoreServerPort(storePrivate, sc_status_p); 396 } 397 398 *server = _sc_server; 399 pthread_mutex_unlock(&_sc_lock); 400 401#ifdef DEBUG 402 SC_log(LOG_DEBUG, "updateServerPort (%@): 0x%x (%d) --> 0x%x (%d)", 403 (storePrivate->name != NULL) ? storePrivate->name : CFSTR("?"), 404 old_port, old_port, 405 *server, *server); 406#endif // DEBUG 407 408 return; 409} 410 411 412static Boolean 413__SCDynamicStoreAddSession(SCDynamicStorePrivateRef storePrivate) 414{ 415 kern_return_t kr = KERN_SUCCESS; 416 CFDataRef myName; /* serialized name */ 417 xmlData_t myNameRef; 418 CFIndex myNameLen; 419 CFDataRef myOptions = NULL; /* serialized options */ 420 xmlData_t myOptionsRef = NULL; 421 CFIndex myOptionsLen = 0; 422 int sc_status = kSCStatusFailed; 423 mach_port_t server; 424 425 if (!_SCSerializeString(storePrivate->name, &myName, (void **)&myNameRef, &myNameLen)) { 426 goto done; 427 } 428 429 /* serialize the options */ 430 if (storePrivate->options != NULL) { 431 if (!_SCSerialize(storePrivate->options, &myOptions, (void **)&myOptionsRef, &myOptionsLen)) { 432 CFRelease(myName); 433 goto done; 434 } 435 } 436 437 /* open a new session with the server */ 438 server = MACH_PORT_NULL; 439 440 441 updateServerPort(storePrivate, &server, &sc_status); 442 443 444 while (server != MACH_PORT_NULL) { 445 // if SCDynamicStore server available 446 447 if (!storePrivate->serverNullSession) { 448 // if SCDynamicStore session 449 kr = configopen(server, 450 myNameRef, 451 (mach_msg_type_number_t)myNameLen, 452 myOptionsRef, 453 (mach_msg_type_number_t)myOptionsLen, 454 &storePrivate->server, 455 (int *)&sc_status); 456 } else { 457 // if NULL session 458 if (storePrivate->server == MACH_PORT_NULL) { 459 // use the [main] SCDynamicStore server port 460 kr = mach_port_mod_refs(mach_task_self(), server, MACH_PORT_RIGHT_SEND, +1); 461 if (kr == KERN_SUCCESS) { 462 storePrivate->server = server; 463 sc_status = kSCStatusOK; 464 } else { 465 if (kr == KERN_INVALID_RIGHT) { 466 // We can get KERN_INVALID_RIGHT if the server dies and we try to 467 // add a send right to a stale (now dead) port name 468 kr = MACH_SEND_INVALID_DEST; 469 } 470 storePrivate->server = MACH_PORT_NULL; 471 } 472 } else { 473 // if the server port we used returned an error 474 storePrivate->server = MACH_PORT_NULL; 475 kr = MACH_SEND_INVALID_DEST; 476 } 477 } 478 479 if (kr == KERN_SUCCESS) { 480 break; 481 } 482 483 // our [cached] server port is not valid 484 if ((kr != MACH_SEND_INVALID_DEST) && (kr != MIG_SERVER_DIED)) { 485 // if we got an unexpected error, don't retry 486 sc_status = kr; 487 break; 488 } 489 490 491 updateServerPort(storePrivate, &server, &sc_status); 492 } 493 __MACH_PORT_DEBUG(TRUE, "*** SCDynamicStoreAddSession", storePrivate->server); 494 495 // clean up 496 CFRelease(myName); 497 if (myOptions != NULL) CFRelease(myOptions); 498 499 done : 500 501 switch (sc_status) { 502 case kSCStatusOK : 503 return TRUE; 504 case BOOTSTRAP_UNKNOWN_SERVICE : 505 SC_log((kr == KERN_SUCCESS) ? LOG_INFO : LOG_ERR, "SCDynamicStore server not available"); 506 sc_status = kSCStatusNoStoreServer; 507 break; 508 default : 509 SC_log((kr == KERN_SUCCESS) ? LOG_INFO : LOG_ERR, "configopen() failed: %d: %s", 510 sc_status, 511 SCErrorString(sc_status)); 512 break; 513 } 514 515 _SCErrorSet(sc_status); 516 return FALSE; 517} 518 519 520__private_extern__ 521SCDynamicStoreRef 522__SCDynamicStoreNullSession(void) 523{ 524 SCDynamicStorePrivateRef storePrivate; 525 Boolean ok = TRUE; 526 __SCThreadSpecificDataRef tsd; 527 528 tsd = __SCGetThreadSpecificData(); 529 if (tsd->_sc_store == NULL) { 530 storePrivate = __SCDynamicStoreCreatePrivate(NULL, 531 CFSTR("NULL session"), 532 NULL, 533 NULL); 534 assert(storePrivate != NULL); 535 storePrivate->serverNullSession = TRUE; 536 tsd->_sc_store = (SCDynamicStoreRef)storePrivate; 537 } 538 539 storePrivate = (SCDynamicStorePrivateRef)tsd->_sc_store; 540 if (storePrivate->server == MACH_PORT_NULL) { 541 ok = __SCDynamicStoreAddSession(storePrivate); 542 } 543 544 return ok ? tsd->_sc_store : NULL; 545} 546 547 548static Boolean 549__SCDynamicStoreReconnect(SCDynamicStoreRef store) 550{ 551 Boolean ok; 552 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; 553 554 ok = __SCDynamicStoreAddSession(storePrivate); 555 return ok; 556} 557 558 559__private_extern__ 560Boolean 561__SCDynamicStoreCheckRetryAndHandleError(SCDynamicStoreRef store, 562 kern_return_t status, 563 int *sc_status, 564 const char *log_str) 565{ 566 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; 567 568 if (status == KERN_SUCCESS) { 569 /* no error */ 570 return FALSE; 571 } 572 573 switch (status) { 574 case MACH_SEND_INVALID_DEST : 575 case MACH_SEND_INVALID_RIGHT : 576 case MIG_SERVER_DIED : 577 /* 578 * the server's gone, remove the session's send (or dead name) right 579 */ 580#ifdef DEBUG 581 SC_log(LOG_DEBUG, "__SCDynamicStoreCheckRetryAndHandleError(%s): %@: 0x%x (%d) --> 0x%x (%d)", 582 log_str, 583 (storePrivate->name != NULL) ? storePrivate->name : CFSTR("?"), 584 storePrivate->server, storePrivate->server, 585 MACH_PORT_NULL, MACH_PORT_NULL); 586#endif // DEBUG 587 (void) mach_port_deallocate(mach_task_self(), storePrivate->server); 588 storePrivate->server = MACH_PORT_NULL; 589 590 /* reconnect */ 591 if (__SCDynamicStoreReconnect(store)) { 592 /* retry needed */ 593 return TRUE; 594 } else { 595 status = SCError(); 596 } 597 ;; 598 599 default : 600 /* 601 * an unexpected error, leave the [session] port alone 602 */ 603#ifdef DEBUG 604 SC_log(LOG_DEBUG, "__SCDynamicStoreCheckRetryAndHandleError(%s): %@: unexpected status=%s (0x%x)", 605 log_str, 606 (storePrivate->name != NULL) ? storePrivate->name : CFSTR("?"), 607 mach_error_string(status), 608 status); 609#endif // DEBUG 610 611 SC_log(LOG_NOTICE, "%s: %s", log_str, mach_error_string(status)); 612 storePrivate->server = MACH_PORT_NULL; 613 ;; 614 } 615 616 *sc_status = status; 617 return FALSE; 618} 619 620 621static void 622pushDisconnect(SCDynamicStoreRef store) 623{ 624 void *context_info; 625 void (*context_release)(const void *); 626 SCDynamicStoreDisconnectCallBack disconnectFunction; 627 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; 628 629 disconnectFunction = storePrivate->disconnectFunction; 630 if (disconnectFunction == NULL) { 631 // if no reconnect callout, push empty notification 632 storePrivate->disconnectForceCallBack = TRUE; 633 return; 634 } 635 636 if (storePrivate->rlsContext.retain != NULL) { 637 context_info = (void *)storePrivate->rlsContext.retain(storePrivate->rlsContext.info); 638 context_release = storePrivate->rlsContext.release; 639 } else { 640 context_info = storePrivate->rlsContext.info; 641 context_release = NULL; 642 } 643 SC_log(LOG_DEBUG, "exec SCDynamicStore disconnect callout"); 644 (*disconnectFunction)(store, context_info); 645 if (context_release) { 646 context_release(context_info); 647 } 648 649 return; 650} 651 652 653__private_extern__ 654Boolean 655__SCDynamicStoreReconnectNotifications(SCDynamicStoreRef store) 656{ 657 dispatch_queue_t dispatchQueue = NULL; 658 __SCDynamicStoreNotificationStatus notifyStatus; 659 Boolean ok = TRUE; 660 CFArrayRef rlList = NULL; 661 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; 662 663#ifdef DEBUG 664 SC_log(LOG_DEBUG, "SCDynamicStore: reconnect notifications (%@)", 665 (storePrivate->name != NULL) ? storePrivate->name : CFSTR("?")); 666#endif // DEBUG 667 668 // save old SCDynamicStore [notification] state 669 notifyStatus = storePrivate->notifyStatus; 670 671 // before tearing down our [old] notifications, make sure we've 672 // retained any information that will be lost when we cancel the 673 // current no-longer-valid handler 674 switch (notifyStatus) { 675 case Using_NotifierInformViaRunLoop : 676 if (storePrivate->rlList != NULL) { 677 rlList = CFArrayCreateCopy(NULL, storePrivate->rlList); 678 } 679 break; 680 case Using_NotifierInformViaDispatch : 681 dispatchQueue = storePrivate->dispatchQueue; 682 if (dispatchQueue != NULL) dispatch_retain(dispatchQueue); 683 break; 684 default : 685 break; 686 } 687 688 // cancel [old] notifications 689 if (!SCDynamicStoreNotifyCancel(store)) { 690 // if we could not cancel / reconnect 691 SC_log(LOG_NOTICE, "SCDynamicStoreNotifyCancel() failed: %s", SCErrorString(SCError())); 692 } 693 694 // set notification keys & patterns 695 if ((storePrivate->keys != NULL) || (storePrivate->patterns)) { 696 ok = SCDynamicStoreSetNotificationKeys(store, 697 storePrivate->keys, 698 storePrivate->patterns); 699 if (!ok) { 700 if (SCError() != BOOTSTRAP_UNKNOWN_SERVICE) { 701 SC_log(LOG_NOTICE, "SCDynamicStoreSetNotificationKeys() failed"); 702 } 703 goto done; 704 } 705 } 706 707 switch (notifyStatus) { 708 case Using_NotifierInformViaRunLoop : { 709 CFIndex i; 710 CFIndex n; 711 CFRunLoopSourceRef rls; 712 713#ifdef DEBUG 714 SC_log(LOG_DEBUG, "SCDynamicStore: reconnecting w/CFRunLoop (%@)", 715 (storePrivate->name != NULL) ? storePrivate->name : CFSTR("?")); 716#endif // DEBUG 717 718 rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0); 719 if (rls == NULL) { 720 if (SCError() != BOOTSTRAP_UNKNOWN_SERVICE) { 721 SC_log(LOG_NOTICE, "SCDynamicStoreCreateRunLoopSource() failed"); 722 } 723 ok = FALSE; 724 break; 725 } 726 727 n = (rlList != NULL) ? CFArrayGetCount(rlList) : 0; 728 for (i = 0; i < n; i += 3) { 729 CFRunLoopRef rl = (CFRunLoopRef)CFArrayGetValueAtIndex(rlList, i+1); 730 CFStringRef rlMode = (CFStringRef) CFArrayGetValueAtIndex(rlList, i+2); 731 732 CFRunLoopAddSource(rl, rls, rlMode); 733 } 734 735 CFRelease(rls); 736 break; 737 } 738 case Using_NotifierInformViaDispatch : 739 740#ifdef DEBUG 741 SC_log(LOG_DEBUG, "SCDynamicStore: reconnecting w/dispatch queue (%@)", 742 (storePrivate->name != NULL) ? storePrivate->name : CFSTR("?")); 743#endif // DEBUG 744 745 ok = SCDynamicStoreSetDispatchQueue(store, dispatchQueue); 746 if (!ok) { 747 if (SCError() != BOOTSTRAP_UNKNOWN_SERVICE) { 748 SC_log(LOG_NOTICE, "SCDynamicStoreSetDispatchQueue() failed"); 749 } 750 goto done; 751 } 752 break; 753 754 default : 755 _SCErrorSet(kSCStatusFailed); 756 ok = FALSE; 757 break; 758 } 759 760 done : 761 762 // cleanup 763 switch (notifyStatus) { 764 case Using_NotifierInformViaRunLoop : 765 if (rlList != NULL) CFRelease(rlList); 766 break; 767 case Using_NotifierInformViaDispatch : 768 if (dispatchQueue != NULL) dispatch_release(dispatchQueue); 769 break; 770 default : 771 break; 772 } 773 774 if (!ok) { 775 SC_log(LOG_NOTICE, "SCDynamicStore server %s, notification (%s) not restored", 776 (SCError() == BOOTSTRAP_UNKNOWN_SERVICE) ? "shutdown" : "failed", 777 notifyType[notifyStatus]); 778 } 779 780 // inform the client 781 pushDisconnect(store); 782 783 return ok; 784} 785 786 787const CFStringRef kSCDynamicStoreUseSessionKeys = CFSTR("UseSessionKeys"); /* CFBoolean */ 788 789 790 791SCDynamicStoreRef 792SCDynamicStoreCreateWithOptions(CFAllocatorRef allocator, 793 CFStringRef name, 794 CFDictionaryRef storeOptions, 795 SCDynamicStoreCallBack callout, 796 SCDynamicStoreContext *context) 797{ 798 Boolean ok; 799 SCDynamicStorePrivateRef storePrivate; 800 801 // allocate and initialize a new session 802 storePrivate = __SCDynamicStoreCreatePrivate(allocator, NULL, callout, context); 803 if (storePrivate == NULL) { 804 return NULL; 805 } 806 807 // set "name" 808 if (_sc_bundleID != NULL) { 809 storePrivate->name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@:%@"), _sc_bundleID, name); 810 } else { 811 storePrivate->name = CFRetain(name); 812 } 813 814 // set "options" 815 816 if (storeOptions != NULL) { 817 storePrivate->options = CFRetain(storeOptions); 818 } 819 820 // establish SCDynamicStore session 821 ok = __SCDynamicStoreAddSession(storePrivate); 822 if (!ok) { 823 CFRelease(storePrivate); 824 storePrivate = NULL; 825 } 826 827 return (SCDynamicStoreRef)storePrivate; 828} 829 830 831SCDynamicStoreRef 832SCDynamicStoreCreate(CFAllocatorRef allocator, 833 CFStringRef name, 834 SCDynamicStoreCallBack callout, 835 SCDynamicStoreContext *context) 836{ 837 return SCDynamicStoreCreateWithOptions(allocator, name, NULL, callout, context); 838} 839 840 841CFTypeID 842SCDynamicStoreGetTypeID(void) { 843 pthread_once(&initialized, __SCDynamicStoreInitialize); /* initialize runtime */ 844 return __kSCDynamicStoreTypeID; 845} 846 847 848Boolean 849SCDynamicStoreSetDisconnectCallBack(SCDynamicStoreRef store, 850 SCDynamicStoreDisconnectCallBack callout) 851{ 852 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; 853 854 if (store == NULL) { 855 /* sorry, you must provide a session */ 856 _SCErrorSet(kSCStatusNoStoreSession); 857 return FALSE; 858 } 859 860 storePrivate->disconnectFunction = callout; 861 return TRUE; 862}