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