Boolean SCDynamicStoreAddWatchedKey(SCDynamicStoreRef store, CFStringRef key, Boolean isRegex) { SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; kern_return_t status; CFDataRef utfKey; /* serialized key */ xmlData_t myKeyRef; CFIndex myKeyLen; int sc_status; 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; } /* serialize the key */ if (!_SCSerializeString(key, &utfKey, (void **)&myKeyRef, &myKeyLen)) { _SCErrorSet(kSCStatusFailed); return FALSE; } retry : /* send the key to the server */ status = notifyadd(storePrivate->server, myKeyRef, myKeyLen, isRegex, (int *)&sc_status); if (__SCDynamicStoreCheckRetryAndHandleError(store, status, &sc_status, "SCDynamicStoreAddWatchedKey notifyadd()")) { goto retry; } /* clean up */ CFRelease(utfKey); if (sc_status != kSCStatusOK) { _SCErrorSet(sc_status); return FALSE; } if (isRegex) { addKey(&storePrivate->patterns, key); } else { addKey(&storePrivate->keys, key); } return TRUE; }
Boolean SCDynamicStoreRemoveValue(SCDynamicStoreRef store, CFStringRef key) { SCDynamicStorePrivateRef storePrivate; kern_return_t status; CFDataRef utfKey; /* serialized key */ xmlData_t myKeyRef; CFIndex myKeyLen; int sc_status; if (store == NULL) { store = __SCDynamicStoreNullSession(); if (store == NULL) { /* sorry, you must provide a session */ _SCErrorSet(kSCStatusNoStoreSession); return FALSE; } } storePrivate = (SCDynamicStorePrivateRef)store; if (storePrivate->server == MACH_PORT_NULL) { /* sorry, you must have an open session to play */ _SCErrorSet(kSCStatusNoStoreServer); return FALSE; } /* serialize the key */ if (!_SCSerializeString(key, &utfKey, (void **)&myKeyRef, &myKeyLen)) { _SCErrorSet(kSCStatusFailed); return FALSE; } retry : /* send the key to the server */ status = configremove(storePrivate->server, myKeyRef, myKeyLen, (int *)&sc_status); if (__SCDynamicStoreCheckRetryAndHandleError(store, status, &sc_status, "SCDynamicStoreRemoveValue configremove()")) { goto retry; } /* clean up */ CFRelease(utfKey); if (sc_status != kSCStatusOK) { _SCErrorSet(sc_status); return FALSE; } return TRUE; }
Boolean SCDynamicStoreNotifyCancel(SCDynamicStoreRef store) { SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; kern_return_t status; int sc_status; if (store == NULL) { /* sorry, you must provide a session */ _SCErrorSet(kSCStatusNoStoreSession); return FALSE; } switch (storePrivate->notifyStatus) { case NotifierNotRegistered : /* if no notifications have been registered */ return TRUE; case Using_NotifierInformViaRunLoop : CFRunLoopSourceInvalidate(storePrivate->rls); storePrivate->rls = NULL; return TRUE; case Using_NotifierInformViaDispatch : (void) SCDynamicStoreSetDispatchQueue(store, NULL); return TRUE; default : break; } if (storePrivate->server == MACH_PORT_NULL) { /* sorry, you must have an open session to play */ sc_status = kSCStatusNoStoreServer; goto done; } status = notifycancel(storePrivate->server, (int *)&sc_status); if (__SCDynamicStoreCheckRetryAndHandleError(store, status, &sc_status, "SCDynamicStoreNotifyCancel notifycancel()")) { sc_status = kSCStatusOK; } done : /* set notifier inactive */ storePrivate->notifyStatus = NotifierNotRegistered; if (sc_status != kSCStatusOK) { _SCErrorSet(sc_status); return FALSE; } return TRUE; }
Boolean SCDynamicStoreNotifySignal(SCDynamicStoreRef store, pid_t pid, int sig) { SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; kern_return_t status; int sc_status; task_t task; 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; } status = task_for_pid(mach_task_self(), pid, &task); if (status != KERN_SUCCESS) { SC_log(LOG_ERR, "task_for_pid() failed: %s", mach_error_string(status)); _SCErrorSet(status); return FALSE; } retry : status = notifyviasignal(storePrivate->server, task, sig, (int *)&sc_status); if (__SCDynamicStoreCheckRetryAndHandleError(store, status, &sc_status, "SCDynamicStoreNotifySignal notifyviasignal()")) { goto retry; } if (status != KERN_SUCCESS) { _SCErrorSet(status); return FALSE; } /* set notifier active */ storePrivate->notifyStatus = Using_NotifierInformViaSignal; return TRUE; }
static void rlsSchedule(void *info, CFRunLoopRef rl, CFStringRef mode) { SCDynamicStoreRef store = (SCDynamicStoreRef)info; SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; #ifdef DEBUG SCLog(_sc_verbose, LOG_DEBUG, CFSTR("schedule notifications for mode %@"), (rl != NULL) ? mode : CFSTR("libdispatch")); #endif /* DEBUG */ if (storePrivate->rlList == NULL) { CFMachPortContext context = { 0 , (void *)store , CFRetain , CFRelease , notifyMPCopyDescription }; mach_port_t oldNotify; mach_port_t port; int sc_status; kern_return_t status; #ifdef DEBUG SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" activate callback runloop source")); #endif /* DEBUG */ /* 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("rlsSchedule mach_port_allocate(): %s"), mach_error_string(status)); return; } 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("rlsSchedule mach_port_insert_right(): %s"), mach_error_string(status)); return; } /* 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("rlsSchedule mach_port_request_notification(): %s"), mach_error_string(status)); return; } if (oldNotify != MACH_PORT_NULL) { SCLog(TRUE, LOG_ERR, CFSTR("rlsSchedule(): oldNotify != MACH_PORT_NULL")); } retry : __MACH_PORT_DEBUG(TRUE, "*** rlsSchedule", port); status = notifyviaport(storePrivate->server, port, 0, (int *)&sc_status); if (__SCDynamicStoreCheckRetryAndHandleError(store, status, &sc_status, "rlsSchedule notifyviaport()")) { goto retry; } if (status != KERN_SUCCESS) { if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { /* 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); return; } if (sc_status != kSCStatusOK) { /* something [else] didn't work, remove our receive right */ (void) mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE, -1); return; } __MACH_PORT_DEBUG(TRUE, "*** rlsSchedule (after notifyviaport)", port); storePrivate->rlsNotifyPort = _SC_CFMachPortCreateWithPort("SCDynamicStore", port, rlsCallback, &context); storePrivate->rlsNotifyRLS = CFMachPortCreateRunLoopSource(NULL, storePrivate->rlsNotifyPort, 0); storePrivate->rlList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); } if ((rl != NULL) && (storePrivate->rlsNotifyRLS != NULL)) { if (!_SC_isScheduled(store, rl, mode, storePrivate->rlList)) { /* * if we are not already scheduled with this runLoop / runLoopMode */ CFRunLoopAddSource(rl, storePrivate->rlsNotifyRLS, mode); __MACH_PORT_DEBUG(TRUE, "*** rlsSchedule (after CFRunLoopAddSource)", CFMachPortGetPort(storePrivate->rlsNotifyPort)); } _SC_schedule(store, rl, mode, storePrivate->rlList); } return; }
static void rlsCancel(void *info, CFRunLoopRef rl, CFStringRef mode) { CFIndex n = 0; SCDynamicStoreRef store = (SCDynamicStoreRef)info; SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; #ifdef DEBUG SCLog(_sc_verbose, LOG_DEBUG, CFSTR("cancel notifications for mode %@"), (rl != NULL) ? mode : CFSTR("libdispatch")); #endif /* DEBUG */ if ((rl != NULL) && (storePrivate->rlsNotifyRLS != NULL)) { if (_SC_unschedule(store, rl, mode, storePrivate->rlList, FALSE)) { /* * if currently scheduled on this runLoop / runLoopMode */ n = CFArrayGetCount(storePrivate->rlList); if (n == 0 || !_SC_isScheduled(store, rl, mode, storePrivate->rlList)) { /* * if we are no longer scheduled to receive notifications for * this runLoop / runLoopMode */ CFRunLoopRemoveSource(rl, storePrivate->rlsNotifyRLS, mode); } } } if (n == 0) { int sc_status; kern_return_t status; #ifdef DEBUG SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" cancel callback runloop source")); #endif /* DEBUG */ __MACH_PORT_DEBUG((storePrivate->rlsNotifyPort != NULL), "*** rlsCancel", CFMachPortGetPort(storePrivate->rlsNotifyPort)); if (storePrivate->rlList != NULL) { CFRelease(storePrivate->rlList); storePrivate->rlList = NULL; } if (storePrivate->rlsNotifyRLS != NULL) { /* invalidate & remove the run loop source */ CFRunLoopSourceInvalidate(storePrivate->rlsNotifyRLS); CFRelease(storePrivate->rlsNotifyRLS); storePrivate->rlsNotifyRLS = NULL; } if (storePrivate->rlsNotifyPort != NULL) { mach_port_t mp; mp = CFMachPortGetPort(storePrivate->rlsNotifyPort); __MACH_PORT_DEBUG((storePrivate->rlsNotifyPort != NULL), "*** rlsCancel (before invalidating/releasing CFMachPort)", mp); /* invalidate and release port */ CFMachPortInvalidate(storePrivate->rlsNotifyPort); CFRelease(storePrivate->rlsNotifyPort); storePrivate->rlsNotifyPort = NULL; /* and, finally, remove our receive right */ (void)mach_port_mod_refs(mach_task_self(), mp, MACH_PORT_RIGHT_RECEIVE, -1); } if (storePrivate->server != MACH_PORT_NULL) { status = notifycancel(storePrivate->server, (int *)&sc_status); (void) __SCDynamicStoreCheckRetryAndHandleError(store, status, &sc_status, "rlsCancel notifycancel()"); if (status != KERN_SUCCESS) { return; } } } return; }
Boolean SCDynamicStoreSetNotificationKeys(SCDynamicStoreRef store, CFArrayRef keys, CFArrayRef patterns) { SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; kern_return_t status; CFDataRef xmlKeys = NULL; /* keys (XML serialized) */ xmlData_t myKeysRef = NULL; /* keys (serialized) */ CFIndex myKeysLen = 0; CFDataRef xmlPatterns = NULL; /* patterns (XML serialized) */ xmlData_t myPatternsRef = NULL; /* patterns (serialized) */ CFIndex myPatternsLen = 0; int sc_status; CFMutableArrayRef tmp; if (store == NULL) { /* sorry, you must provide a session */ _SCErrorSet(kSCStatusNoStoreSession); return FALSE; } if (storePrivate->server == MACH_PORT_NULL) { _SCErrorSet(kSCStatusNoStoreServer); return FALSE; /* you must have an open session to play */ } /* serialize the keys */ if (keys != NULL) { if (!_SCSerialize(keys, &xmlKeys, (void **)&myKeysRef, &myKeysLen)) { _SCErrorSet(kSCStatusFailed); return FALSE; } } /* serialize the patterns */ if (patterns != NULL) { if (!_SCSerialize(patterns, &xmlPatterns, (void **)&myPatternsRef, &myPatternsLen)) { if (xmlKeys != NULL) CFRelease(xmlKeys); _SCErrorSet(kSCStatusFailed); return FALSE; } } retry : /* send the keys and patterns, fetch the associated result from the server */ status = notifyset(storePrivate->server, myKeysRef, myKeysLen, myPatternsRef, myPatternsLen, (int *)&sc_status); if (__SCDynamicStoreCheckRetryAndHandleError(store, status, &sc_status, "SCDynamicStoreSetNotificationKeys notifyset()")) { goto retry; } /* clean up */ if (xmlKeys != NULL) CFRelease(xmlKeys); if (xmlPatterns != NULL) CFRelease(xmlPatterns); if (sc_status != kSCStatusOK) { _SCErrorSet(sc_status); return FALSE; } /* in case we need to re-connect, save the keys/patterns */ tmp = (keys != NULL) ? CFArrayCreateMutableCopy(NULL, 0, keys) : NULL; if (storePrivate->keys != NULL) CFRelease(storePrivate->keys); storePrivate->keys = tmp; tmp = (patterns != NULL) ? CFArrayCreateMutableCopy(NULL, 0, patterns) : NULL; if (storePrivate->patterns != NULL) CFRelease(storePrivate->patterns); storePrivate->patterns = tmp; return TRUE; }
Boolean SCDynamicStoreSetMultiple(SCDynamicStoreRef store, CFDictionaryRef keysToSet, CFArrayRef keysToRemove, CFArrayRef keysToNotify) { SCDynamicStorePrivateRef storePrivate; kern_return_t status; CFDataRef xmlSet = NULL; /* key/value pairs to set (XML serialized) */ xmlData_t mySetRef = NULL; /* key/value pairs to set (serialized) */ CFIndex mySetLen = 0; CFDataRef xmlRemove = NULL; /* keys to remove (XML serialized) */ xmlData_t myRemoveRef = NULL; /* keys to remove (serialized) */ CFIndex myRemoveLen = 0; CFDataRef xmlNotify = NULL; /* keys to notify (XML serialized) */ xmlData_t myNotifyRef = NULL; /* keys to notify (serialized) */ CFIndex myNotifyLen = 0; int sc_status; if (store == NULL) { store = __SCDynamicStoreNullSession(); if (store == NULL) { /* sorry, you must provide a session */ _SCErrorSet(kSCStatusNoStoreSession); return FALSE; } } storePrivate = (SCDynamicStorePrivateRef)store; if (storePrivate->server == MACH_PORT_NULL) { _SCErrorSet(kSCStatusNoStoreServer); return FALSE; /* you must have an open session to play */ } /* serialize the key/value pairs to set*/ if (keysToSet != NULL) { CFDictionaryRef newInfo; Boolean ok; newInfo = _SCSerializeMultiple(keysToSet); if (newInfo == NULL) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } ok = _SCSerialize(newInfo, &xmlSet, (void **)&mySetRef, &mySetLen); CFRelease(newInfo); if (!ok) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } } /* serialize the keys to remove */ if (keysToRemove != NULL) { if (!_SCSerialize(keysToRemove, &xmlRemove, (void **)&myRemoveRef, &myRemoveLen)) { if (xmlSet != NULL) CFRelease(xmlSet); _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } } /* serialize the keys to notify */ if (keysToNotify != NULL) { if (!_SCSerialize(keysToNotify, &xmlNotify, (void **)&myNotifyRef, &myNotifyLen)) { if (xmlSet != NULL) CFRelease(xmlSet); if (xmlRemove != NULL) CFRelease(xmlRemove); _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } } retry : /* send the keys and patterns, fetch the associated result from the server */ status = configset_m(storePrivate->server, mySetRef, mySetLen, myRemoveRef, myRemoveLen, myNotifyRef, myNotifyLen, (int *)&sc_status); if (__SCDynamicStoreCheckRetryAndHandleError(store, status, &sc_status, "SCDynamicStoreSetMultiple configset_m()")) { goto retry; } /* clean up */ if (xmlSet != NULL) CFRelease(xmlSet); if (xmlRemove != NULL) CFRelease(xmlRemove); if (xmlNotify != NULL) CFRelease(xmlNotify); if (sc_status != kSCStatusOK) { _SCErrorSet(sc_status); return FALSE; } return TRUE; }
Boolean SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFPropertyListRef value) { SCDynamicStorePrivateRef storePrivate; kern_return_t status; CFDataRef utfKey; /* serialized key */ xmlData_t myKeyRef; CFIndex myKeyLen; CFDataRef xmlData; /* serialized data */ xmlData_t myDataRef; CFIndex myDataLen; int sc_status; int newInstance; if (store == NULL) { store = __SCDynamicStoreNullSession(); if (store == NULL) { /* sorry, you must provide a session */ _SCErrorSet(kSCStatusNoStoreSession); return FALSE; } } storePrivate = (SCDynamicStorePrivateRef)store; if (storePrivate->server == MACH_PORT_NULL) { /* sorry, you must have an open session to play */ _SCErrorSet(kSCStatusNoStoreServer); return FALSE; } /* serialize the key */ if (!_SCSerializeString(key, &utfKey, (void **)&myKeyRef, &myKeyLen)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } /* serialize the data */ if (!_SCSerialize(value, &xmlData, (void **)&myDataRef, &myDataLen)) { CFRelease(utfKey); _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } retry : /* send the key & data to the server, get new instance id */ status = configset(storePrivate->server, myKeyRef, myKeyLen, myDataRef, myDataLen, 0, &newInstance, (int *)&sc_status); if (__SCDynamicStoreCheckRetryAndHandleError(store, status, &sc_status, "SCDynamicStoreSetValue configset()")) { goto retry; } /* clean up */ CFRelease(utfKey); CFRelease(xmlData); if (sc_status != kSCStatusOK) { _SCErrorSet(sc_status); return FALSE; } return TRUE; }