-Boolean
-SCDynamicStoreNotifyCallback(SCDynamicStoreRef store,
- CFRunLoopRef runLoop,
- SCDynamicStoreCallBack_v1 func,
- void *arg)
-{
- SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
- kern_return_t status;
- mach_port_t port;
- mach_port_t oldNotify;
- int sc_status;
- CFMachPortContext context = { 0
- , (void *)store
- , CFRetain
- , CFRelease
- , notifyMPCopyDescription
- };
-
- if (store == NULL) {
- /* sorry, you must provide a session */
- _SCErrorSet(kSCStatusNoStoreSession);
- return FALSE;
- }
-
- if (storePrivate->server == MACH_PORT_NULL) {
- /* sorry, you must have an open session to play */
- _SCErrorSet(kSCStatusNoStoreServer);
- return FALSE;
- }
-
- if (storePrivate->notifyStatus != NotifierNotRegistered) {
- /* sorry, you can only have one notification registered at once */
- _SCErrorSet(kSCStatusNotifierActive);
- return FALSE;
- }
-
- /* Allocating port (for server response) */
- status = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
- if (status != KERN_SUCCESS) {
- SCLog(TRUE, LOG_ERR, CFSTR("mach_port_allocate(): %s"), mach_error_string(status));
- _SCErrorSet(status);
- return FALSE;
- }
-
- status = mach_port_insert_right(mach_task_self(),
- port,
- port,
- MACH_MSG_TYPE_MAKE_SEND);
- if (status != KERN_SUCCESS) {
- /*
- * We can't insert a send right into our own port! This should
- * only happen if someone stomped on OUR port (so let's leave
- * the port alone).
- */
- SCLog(TRUE, LOG_ERR, CFSTR("mach_port_insert_right(): %s"), mach_error_string(status));
- _SCErrorSet(status);
- return FALSE;
- }
-
- /* Request a notification when/if the server dies */
- status = mach_port_request_notification(mach_task_self(),
- port,
- MACH_NOTIFY_NO_SENDERS,
- 1,
- port,
- MACH_MSG_TYPE_MAKE_SEND_ONCE,
- &oldNotify);
- if (status != KERN_SUCCESS) {
- /*
- * We can't request a notification for our own port! This should
- * only happen if someone stomped on OUR port (so let's leave
- * the port alone).
- */
- SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyCallback mach_port_request_notification(): %s"), mach_error_string(status));
- _SCErrorSet(status);
- return FALSE;
- }
-
- if (oldNotify != MACH_PORT_NULL) {
- SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyCallback(): oldNotify != MACH_PORT_NULL"));
- }
-
- /* Requesting notification via mach port */
- status = notifyviaport(storePrivate->server,
- port,
- 0,
- (int *)&sc_status);
-
- if (status != KERN_SUCCESS) {
- if (status == MACH_SEND_INVALID_DEST) {
- /* the server's gone and our session port's dead, remove the dead name right */
- (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
- } else {
- /* we got an unexpected error, leave the [session] port alone */
- SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyCallback notifyviaport(): %s"), mach_error_string(status));
- }
- storePrivate->server = MACH_PORT_NULL;
-
- if (status == MACH_SEND_INVALID_DEST) {
- /* remove the send right that we tried (but failed) to pass to the server */
- (void) mach_port_deallocate(mach_task_self(), port);
- }
-
- /* remove our receive right */
- (void) mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE, -1);
- _SCErrorSet(status);
- return FALSE;
- }
-
- if (sc_status != kSCStatusOK) {
- _SCErrorSet(sc_status);
- return FALSE;
- }
-
- /* set notifier active */
- storePrivate->notifyStatus = Using_NotifierInformViaCallback;
-
- /* Creating/adding a run loop source for the port */
- __MACH_PORT_DEBUG(TRUE, "*** SCDynamicStoreNotifyCallback", port);
- storePrivate->callbackArgument = arg;
- storePrivate->callbackFunction = func;
- storePrivate->callbackPort = CFMachPortCreateWithPort(NULL, port, informCallback, &context, NULL);
- storePrivate->callbackRLS = CFMachPortCreateRunLoopSource(NULL, storePrivate->callbackPort, 0);
- CFRunLoopAddSource(runLoop, storePrivate->callbackRLS, kCFRunLoopDefaultMode);
-
- return TRUE;
-}
-
-