]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCDNotifierInformViaCallback.c
configd-699.30.1.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCDNotifierInformViaCallback.c
1 /*
2 * Copyright (c) 2000-2005, 2008-2014 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 31, 2000 Allan Nathanson <ajn@apple.com>
31 * - initial revision
32 */
33
34 #include <Availability.h>
35 #include <TargetConditionals.h>
36 #include <sys/cdefs.h>
37 #include <dispatch/dispatch.h>
38 #include <mach/mach.h>
39 #include <mach/mach_error.h>
40
41 #include <SystemConfiguration/SystemConfiguration.h>
42 #include <SystemConfiguration/SCPrivate.h>
43 #include "SCDynamicStoreInternal.h"
44 #include "config.h" /* MiG generated file */
45
46 #if !TARGET_IPHONE_SIMULATOR || (defined(IPHONE_SIMULATOR_HOST_MIN_VERSION_REQUIRED) && (IPHONE_SIMULATOR_HOST_MIN_VERSION_REQUIRED >= 1090))
47 #define HAVE_MACHPORT_GUARDS
48 #endif
49
50
51 static CFStringRef
52 notifyMPCopyDescription(const void *info)
53 {
54 SCDynamicStoreRef store = (SCDynamicStoreRef)info;
55
56 return CFStringCreateWithFormat(NULL,
57 NULL,
58 CFSTR("<SCDynamicStore notification MP> {store = %p}"),
59 store);
60 }
61
62
63 static void
64 rlsCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
65 {
66 mach_no_senders_notification_t *buf = msg;
67 mach_msg_id_t msgid = buf->not_header.msgh_id;
68 SCDynamicStoreRef store = (SCDynamicStoreRef)info;
69 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
70
71 if (msgid == MACH_NOTIFY_NO_SENDERS) {
72 /* the server died, disable additional callbacks */
73 #ifdef DEBUG
74 SCLog(_sc_verbose, LOG_INFO, CFSTR(" rlsCallback(), notifier port closed"));
75 #endif /* DEBUG */
76
77 #ifdef DEBUG
78 if (port != storePrivate->rlsNotifyPort) {
79 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("rlsCallback(), why is port != rlsNotifyPort?"));
80 }
81 #endif /* DEBUG */
82
83 /* re-establish notification and inform the client */
84 (void)__SCDynamicStoreReconnectNotifications(store);
85 }
86
87 /* signal the real runloop source */
88 if (storePrivate->rls != NULL) {
89 CFRunLoopSourceSignal(storePrivate->rls);
90 }
91 return;
92 }
93
94
95 static void
96 rlsSchedule(void *info, CFRunLoopRef rl, CFStringRef mode)
97 {
98 SCDynamicStoreRef store = (SCDynamicStoreRef)info;
99 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
100
101 #ifdef DEBUG
102 SCLog(_sc_verbose, LOG_DEBUG,
103 CFSTR("schedule notifications for mode %@"),
104 (rl != NULL) ? mode : CFSTR("libdispatch"));
105 #endif /* DEBUG */
106
107 if (storePrivate->rlList == NULL) {
108 CFMachPortContext context = { 0
109 , (void *)store
110 , CFRetain
111 , CFRelease
112 , notifyMPCopyDescription
113 };
114 kern_return_t kr;
115 mach_port_t oldNotify;
116 #ifdef HAVE_MACHPORT_GUARDS
117 mach_port_options_t opts;
118 #endif // HAVE_MACHPORT_GUARDS
119 mach_port_t port;
120 int sc_status;
121
122 #ifdef DEBUG
123 SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" activate callback runloop source"));
124 #endif /* DEBUG */
125
126 /* allocate a mach port for the SCDynamicStore notifications */
127
128 retry_allocate :
129
130 #ifdef HAVE_MACHPORT_GUARDS
131 bzero(&opts, sizeof(opts));
132 opts.flags = MPO_CONTEXT_AS_GUARD|MPO_INSERT_SEND_RIGHT;
133
134 kr = mach_port_construct(mach_task_self(), &opts, store, &port);
135 #else // HAVE_MACHPORT_GUARDS
136 kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
137 #endif // HAVE_MACHPORT_GUARDS
138
139 if (kr != KERN_SUCCESS) {
140 SCLog(TRUE, LOG_ERR, CFSTR("rlsSchedule could not allocate mach port: %s"), mach_error_string(kr));
141 if ((kr == KERN_NO_SPACE) || (kr == KERN_RESOURCE_SHORTAGE)) {
142 sleep(1);
143 goto retry_allocate;
144 } else {
145 return;
146 }
147 }
148
149 #ifndef HAVE_MACHPORT_GUARDS
150 kr = mach_port_insert_right(mach_task_self(),
151 port,
152 port,
153 MACH_MSG_TYPE_MAKE_SEND);
154 if (kr != KERN_SUCCESS) {
155 /*
156 * We can't insert a send right into our own port! This should
157 * only happen if someone stomped on OUR port (so let's leave
158 * the port alone).
159 */
160 SCLog(TRUE, LOG_ERR, CFSTR("rlsSchedule mach_port_insert_right(): %s"), mach_error_string(kr));
161 return;
162 }
163 #endif // HAVE_MACHPORT_GUARDS
164
165 /* Request a notification when/if the server dies */
166 kr = mach_port_request_notification(mach_task_self(),
167 port,
168 MACH_NOTIFY_NO_SENDERS,
169 1,
170 port,
171 MACH_MSG_TYPE_MAKE_SEND_ONCE,
172 &oldNotify);
173 if (kr != KERN_SUCCESS) {
174 /*
175 * We can't request a notification for our own port! This should
176 * only happen if someone stomped on OUR port (so let's leave
177 * the port alone).
178 */
179 SCLog(TRUE, LOG_ERR, CFSTR("rlsSchedule mach_port_request_notification(): %s"), mach_error_string(kr));
180 return;
181 }
182
183 if (oldNotify != MACH_PORT_NULL) {
184 SCLog(TRUE, LOG_ERR, CFSTR("rlsSchedule(): oldNotify != MACH_PORT_NULL"));
185 }
186
187 retry :
188
189 __MACH_PORT_DEBUG(TRUE, "*** rlsSchedule", port);
190 kr = notifyviaport(storePrivate->server, port, 0, (int *)&sc_status);
191
192 if (__SCDynamicStoreCheckRetryAndHandleError(store,
193 kr,
194 &sc_status,
195 "rlsSchedule notifyviaport()")) {
196 goto retry;
197 }
198
199 if (kr != KERN_SUCCESS) {
200 if ((kr == MACH_SEND_INVALID_DEST) || (kr == MIG_SERVER_DIED)) {
201 /* remove the send right that we tried (but failed) to pass to the server */
202 (void) mach_port_deallocate(mach_task_self(), port);
203 }
204
205 /* remove our receive right */
206 #ifdef HAVE_MACHPORT_GUARDS
207 (void) mach_port_destruct(mach_task_self(), port, 0, store);
208 #else // HAVE_MACHPORT_GUARDS
209 (void) mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE, -1);
210 #endif // HAVE_MACHPORT_GUARDS
211 return;
212 }
213
214 if (sc_status != kSCStatusOK) {
215 /* something [else] didn't work, remove our receive right */
216 #ifdef HAVE_MACHPORT_GUARDS
217 (void) mach_port_destruct(mach_task_self(), port, 0, store);
218 #else // HAVE_MACHPORT_GUARDS
219 (void) mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE, -1);
220 #endif // HAVE_MACHPORT_GUARDS
221 return;
222 }
223
224 __MACH_PORT_DEBUG(TRUE, "*** rlsSchedule (after notifyviaport)", port);
225 storePrivate->rlsNotifyPort = _SC_CFMachPortCreateWithPort("SCDynamicStore",
226 port,
227 rlsCallback,
228 &context);
229 storePrivate->rlsNotifyRLS = CFMachPortCreateRunLoopSource(NULL, storePrivate->rlsNotifyPort, 0);
230
231 storePrivate->rlList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
232 }
233
234 if ((rl != NULL) && (storePrivate->rlsNotifyRLS != NULL)) {
235 if (!_SC_isScheduled(store, rl, mode, storePrivate->rlList)) {
236 /*
237 * if we are not already scheduled with this runLoop / runLoopMode
238 */
239 CFRunLoopAddSource(rl, storePrivate->rlsNotifyRLS, mode);
240 __MACH_PORT_DEBUG(TRUE, "*** rlsSchedule (after CFRunLoopAddSource)", CFMachPortGetPort(storePrivate->rlsNotifyPort));
241 }
242
243 _SC_schedule(store, rl, mode, storePrivate->rlList);
244 }
245
246 return;
247 }
248
249
250 static void
251 rlsCancel(void *info, CFRunLoopRef rl, CFStringRef mode)
252 {
253 CFIndex n = 0;
254 SCDynamicStoreRef store = (SCDynamicStoreRef)info;
255 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
256
257 #ifdef DEBUG
258 SCLog(_sc_verbose, LOG_DEBUG,
259 CFSTR("cancel notifications for mode %@"),
260 (rl != NULL) ? mode : CFSTR("libdispatch"));
261 #endif /* DEBUG */
262
263 if ((rl != NULL) && (storePrivate->rlsNotifyRLS != NULL)) {
264 if (_SC_unschedule(store, rl, mode, storePrivate->rlList, FALSE)) {
265 /*
266 * if currently scheduled on this runLoop / runLoopMode
267 */
268 n = CFArrayGetCount(storePrivate->rlList);
269 if (n == 0 || !_SC_isScheduled(store, rl, mode, storePrivate->rlList)) {
270 /*
271 * if we are no longer scheduled to receive notifications for
272 * this runLoop / runLoopMode
273 */
274 CFRunLoopRemoveSource(rl, storePrivate->rlsNotifyRLS, mode);
275 }
276 }
277 }
278
279 if (n == 0) {
280 int sc_status;
281 kern_return_t kr;
282
283 #ifdef DEBUG
284 SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" cancel callback runloop source"));
285 #endif /* DEBUG */
286 __MACH_PORT_DEBUG((storePrivate->rlsNotifyPort != NULL),
287 "*** rlsCancel",
288 CFMachPortGetPort(storePrivate->rlsNotifyPort));
289
290 if (storePrivate->rlList != NULL) {
291 CFRelease(storePrivate->rlList);
292 storePrivate->rlList = NULL;
293 }
294
295 if (storePrivate->rlsNotifyRLS != NULL) {
296 /* invalidate & remove the run loop source */
297 CFRunLoopSourceInvalidate(storePrivate->rlsNotifyRLS);
298 CFRelease(storePrivate->rlsNotifyRLS);
299 storePrivate->rlsNotifyRLS = NULL;
300 }
301
302 if (storePrivate->rlsNotifyPort != NULL) {
303 mach_port_t mp;
304
305 mp = CFMachPortGetPort(storePrivate->rlsNotifyPort);
306 __MACH_PORT_DEBUG((storePrivate->rlsNotifyPort != NULL),
307 "*** rlsCancel (before invalidating/releasing CFMachPort)",
308 mp);
309
310 /* invalidate and release port */
311 CFMachPortInvalidate(storePrivate->rlsNotifyPort);
312 CFRelease(storePrivate->rlsNotifyPort);
313 storePrivate->rlsNotifyPort = NULL;
314
315 /* and, finally, remove our receive right */
316 #ifdef HAVE_MACHPORT_GUARDS
317 (void) mach_port_destruct(mach_task_self(), mp, 0, store);
318 #else // HAVE_MACHPORT_GUARDS
319 (void) mach_port_mod_refs(mach_task_self(), mp, MACH_PORT_RIGHT_RECEIVE, -1);
320 #endif // HAVE_MACHPORT_GUARDS
321 }
322
323 if (storePrivate->server != MACH_PORT_NULL) {
324 kr = notifycancel(storePrivate->server, (int *)&sc_status);
325
326 (void) __SCDynamicStoreCheckRetryAndHandleError(store,
327 kr,
328 &sc_status,
329 "rlsCancel notifycancel()");
330
331 if (kr != KERN_SUCCESS) {
332 return;
333 }
334 }
335 }
336
337 return;
338 }
339
340
341 static void
342 rlsPerform(void *info)
343 {
344 CFArrayRef changedKeys;
345 void *context_info;
346 void (*context_release)(const void *);
347 SCDynamicStoreCallBack rlsFunction;
348 SCDynamicStoreRef store = (SCDynamicStoreRef)info;
349 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
350
351 #ifdef DEBUG
352 SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" executing notification function"));
353 #endif /* DEBUG */
354
355 changedKeys = SCDynamicStoreCopyNotifiedKeys(store);
356 if (storePrivate->disconnectForceCallBack) {
357 storePrivate->disconnectForceCallBack = FALSE;
358 if (changedKeys == NULL) {
359 changedKeys = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
360 }
361 } else {
362 if (changedKeys == NULL) {
363 /* if no changes or something happened to the server */
364 return;
365 } else if (CFArrayGetCount(changedKeys) == 0) {
366 goto done;
367 }
368 }
369
370 rlsFunction = storePrivate->rlsFunction;
371
372 if (storePrivate->rlsContext.retain != NULL) {
373 context_info = (void *)storePrivate->rlsContext.retain(storePrivate->rlsContext.info);
374 context_release = storePrivate->rlsContext.release;
375 } else {
376 context_info = storePrivate->rlsContext.info;
377 context_release = NULL;
378 }
379 if (rlsFunction != NULL) {
380 (*rlsFunction)(store, changedKeys, context_info);
381 }
382 if (context_release != NULL) {
383 context_release(context_info);
384 }
385
386 done :
387
388 CFRelease(changedKeys);
389 return;
390 }
391
392
393 static CFTypeRef
394 rlsRetain(CFTypeRef cf)
395 {
396 SCDynamicStoreRef store = (SCDynamicStoreRef)cf;
397 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
398
399 switch (storePrivate->notifyStatus) {
400 case NotifierNotRegistered :
401 /* mark RLS active */
402 storePrivate->notifyStatus = Using_NotifierInformViaRunLoop;
403 /* keep a reference to the store */
404 CFRetain(store);
405 break;
406 case Using_NotifierInformViaRunLoop :
407 break;
408 default :
409 SCLog(TRUE, LOG_ERR, CFSTR("rlsRetain() error: notifyStatus=%d"), storePrivate->notifyStatus);
410 break;
411 }
412
413 return cf;
414 }
415
416
417 static void
418 rlsRelease(CFTypeRef cf)
419 {
420 SCDynamicStoreRef store = (SCDynamicStoreRef)cf;
421 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
422
423 switch (storePrivate->notifyStatus) {
424 case NotifierNotRegistered :
425 break;
426 case Using_NotifierInformViaRunLoop :
427 /* mark RLS inactive */
428 storePrivate->notifyStatus = NotifierNotRegistered;
429 storePrivate->rls = NULL;
430
431 /* release our reference to the store */
432 CFRelease(store);
433 break;
434 default :
435 SCLog(TRUE, LOG_ERR, CFSTR("rlsRelease() error: notifyStatus=%d"), storePrivate->notifyStatus);
436 break;
437 }
438
439 return;
440 }
441
442
443 static CFStringRef
444 rlsCopyDescription(const void *info)
445 {
446 CFMutableStringRef result;
447 SCDynamicStoreRef store = (SCDynamicStoreRef)info;
448 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
449
450 result = CFStringCreateMutable(NULL, 0);
451 CFStringAppendFormat(result, NULL, CFSTR("<SCDynamicStore RLS> {"));
452 CFStringAppendFormat(result, NULL, CFSTR("store = %p"), store);
453 if (storePrivate->notifyStatus == Using_NotifierInformViaRunLoop) {
454 CFStringRef description = NULL;
455
456 CFStringAppendFormat(result, NULL, CFSTR(", callout = %p"), storePrivate->rlsFunction);
457
458 if ((storePrivate->rlsContext.info != NULL) && (storePrivate->rlsContext.copyDescription != NULL)) {
459 description = (*storePrivate->rlsContext.copyDescription)(storePrivate->rlsContext.info);
460 }
461 if (description == NULL) {
462 description = CFStringCreateWithFormat(NULL, NULL, CFSTR("<SCDynamicStore context %p>"), storePrivate->rlsContext.info);
463 }
464 if (description == NULL) {
465 description = CFRetain(CFSTR("<no description>"));
466 }
467 CFStringAppendFormat(result, NULL, CFSTR(", context = %@"), description);
468 CFRelease(description);
469 }
470 CFStringAppendFormat(result, NULL, CFSTR("}"));
471
472 return result;
473 }
474
475
476 CFRunLoopSourceRef
477 SCDynamicStoreCreateRunLoopSource(CFAllocatorRef allocator,
478 SCDynamicStoreRef store,
479 CFIndex order)
480 {
481 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
482
483 if (store == NULL) {
484 /* sorry, you must provide a session */
485 _SCErrorSet(kSCStatusNoStoreSession);
486 return NULL;
487 }
488
489 if (storePrivate->server == MACH_PORT_NULL) {
490 /* sorry, you must have an open session to play */
491 _SCErrorSet(kSCStatusNoStoreServer);
492 return NULL;
493 }
494
495 switch (storePrivate->notifyStatus) {
496 case NotifierNotRegistered :
497 case Using_NotifierInformViaRunLoop :
498 /* OK to enable runloop notification */
499 break;
500 default :
501 /* sorry, you can only have one notification registered at once */
502 _SCErrorSet(kSCStatusNotifierActive);
503 return NULL;
504 }
505
506 if (storePrivate->rls != NULL) {
507 CFRetain(storePrivate->rls);
508 } else {
509 CFRunLoopSourceContext context = { 0 // version
510 , (void *)store // info
511 , rlsRetain // retain
512 , rlsRelease // release
513 , rlsCopyDescription // copyDescription
514 , CFEqual // equal
515 , CFHash // hash
516 , rlsSchedule // schedule
517 , rlsCancel // cancel
518 , rlsPerform // perform
519 };
520
521 storePrivate->rls = CFRunLoopSourceCreate(allocator, order, &context);
522 if (storePrivate->rls == NULL) {
523 _SCErrorSet(kSCStatusFailed);
524 }
525 }
526
527 return storePrivate->rls;
528 }
529
530
531 Boolean
532 SCDynamicStoreSetDispatchQueue(SCDynamicStoreRef store, dispatch_queue_t queue)
533 {
534 dispatch_group_t drainGroup = NULL;
535 dispatch_queue_t drainQueue = NULL;
536 dispatch_group_t group = NULL;
537 mach_port_t mp;
538 Boolean ok = FALSE;
539 dispatch_source_t source;
540 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
541
542 if (store == NULL) {
543 // sorry, you must provide a session
544 _SCErrorSet(kSCStatusNoStoreSession);
545 return FALSE;
546 }
547
548 if (queue == NULL) {
549 if (storePrivate->dispatchQueue == NULL) {
550 _SCErrorSet(kSCStatusInvalidArgument);
551 return FALSE;
552 }
553
554 ok = TRUE;
555 goto cleanup;
556 }
557
558 if (storePrivate->server == MACH_PORT_NULL) {
559 // sorry, you must have an open session to play
560 _SCErrorSet(kSCStatusNoStoreServer);
561 return FALSE;
562 }
563
564 if ((storePrivate->dispatchQueue != NULL) || (storePrivate->rls != NULL)) {
565 _SCErrorSet(kSCStatusInvalidArgument);
566 return FALSE;
567 }
568
569 if (storePrivate->notifyStatus != NotifierNotRegistered) {
570 // sorry, you can only have one notification registered at once...
571 _SCErrorSet(kSCStatusNotifierActive);
572 return FALSE;
573 }
574
575 /*
576 * mark our using of the SCDynamicStore notifications, create and schedule
577 * the notification port (storePrivate->rlsNotifyPort), and a bunch of other
578 * "setup"
579 */
580 storePrivate->notifyStatus = Using_NotifierInformViaDispatch;
581 rlsSchedule((void*)store, NULL, NULL);
582 if (storePrivate->rlsNotifyPort == NULL) {
583 /* if we could not schedule the notification */
584 _SCErrorSet(kSCStatusFailed);
585 goto cleanup;
586 }
587
588 // retain the dispatch queue
589 storePrivate->dispatchQueue = queue;
590 dispatch_retain(storePrivate->dispatchQueue);
591
592 //
593 // We've taken a reference to the callers dispatch_queue and we
594 // want to hold on to that reference until we've processed any/all
595 // notifications. To facilitate this we create a group, dispatch
596 // any notification blocks to via that group, and when the caller
597 // has told us to stop the notifications (unschedule) we wait for
598 // the group to empty and use the group's finalizer to release
599 // our reference to the SCDynamicStore.
600 //
601 group = dispatch_group_create();
602 storePrivate->dispatchGroup = group;
603 CFRetain(store);
604 dispatch_set_context(storePrivate->dispatchGroup, (void *)store);
605 dispatch_set_finalizer_f(storePrivate->dispatchGroup, (dispatch_function_t)CFRelease);
606
607 // create a dispatch source for the mach notifications
608 mp = CFMachPortGetPort(storePrivate->rlsNotifyPort);
609 source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, mp, 0, queue);
610 if (source == NULL) {
611 SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStore dispatch_source_create() failed"));
612 _SCErrorSet(kSCStatusFailed);
613 goto cleanup;
614 }
615
616 dispatch_source_set_event_handler(source, ^{
617 kern_return_t kr;
618 mach_msg_id_t msgid;
619 union {
620 u_int8_t buf[sizeof(mach_msg_empty_t) + MAX_TRAILER_SIZE];
621 mach_msg_empty_rcv_t msg;
622 mach_no_senders_notification_t no_senders;
623 } notify_msg;
624
625 kr = mach_msg(&notify_msg.msg.header, // msg
626 MACH_RCV_MSG, // options
627 0, // send_size
628 sizeof(notify_msg), // rcv_size
629 mp, // rcv_name
630 MACH_MSG_TIMEOUT_NONE, // timeout
631 MACH_PORT_NULL); // notify
632 if (kr != KERN_SUCCESS) {
633 SCLog(TRUE, LOG_ERR,
634 CFSTR("SCDynamicStore notification handler, kr=0x%x"),
635 kr);
636 return;
637 }
638
639 msgid = notify_msg.msg.header.msgh_id;
640
641 CFRetain(store);
642 dispatch_group_async(group, queue, ^{
643 if (msgid == MACH_NOTIFY_NO_SENDERS) {
644 // re-establish notification and inform the client
645 (void)__SCDynamicStoreReconnectNotifications(store);
646 }
647 rlsPerform(storePrivate);
648 CFRelease(store);
649 });
650 });
651
652 dispatch_source_set_cancel_handler(source, ^{
653 dispatch_release(source);
654 });
655
656 storePrivate->dispatchSource = source;
657 dispatch_resume(source);
658
659 return TRUE;
660
661 cleanup :
662
663 CFRetain(store);
664
665 if (storePrivate->dispatchSource != NULL) {
666 dispatch_source_cancel(storePrivate->dispatchSource);
667 storePrivate->dispatchSource = NULL;
668 }
669 drainGroup = storePrivate->dispatchGroup;
670 storePrivate->dispatchGroup = NULL;
671 drainQueue = storePrivate->dispatchQueue;
672 storePrivate->dispatchQueue = NULL;
673
674 rlsCancel((void*)store, NULL, NULL);
675
676 if (drainGroup != NULL) {
677 dispatch_group_notify(drainGroup, drainQueue, ^{
678 // release group/queue references
679 dispatch_release(drainQueue);
680 dispatch_release(drainGroup); // releases our store reference
681 });
682 }
683
684 storePrivate->notifyStatus = NotifierNotRegistered;
685
686 CFRelease(store);
687
688 return ok;
689 }