#include <unistd.h>
#include "configd.h"
#include "configd_server.h"
#include "session.h"
__private_extern__ CFMutableDictionaryRef storeData = NULL;
__private_extern__ CFMutableDictionaryRef patternData = NULL;
__private_extern__ CFMutableSetRef changedKeys = NULL;
__private_extern__ CFMutableSetRef deferredRemovals = NULL;
__private_extern__ CFMutableSetRef removedSessionKeys = NULL;
__private_extern__ CFMutableSetRef needsNotification = NULL;
__private_extern__
void
_addWatcher(CFNumberRef sessionNum, CFStringRef watchedKey)
{
CFDictionaryRef dict;
CFMutableDictionaryRef newDict;
CFArrayRef watchers;
CFMutableArrayRef newWatchers;
CFArrayRef watcherRefs;
CFMutableArrayRef newWatcherRefs;
CFIndex i;
int refCnt;
CFNumberRef refNum;
dict = CFDictionaryGetValue(storeData, watchedKey);
if (dict != NULL) {
newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
} else {
newDict = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
watchers = CFDictionaryGetValue(newDict, kSCDWatchers);
watcherRefs = CFDictionaryGetValue(newDict, kSCDWatcherRefs);
if (watchers) {
newWatchers = CFArrayCreateMutableCopy(NULL, 0, watchers);
newWatcherRefs = CFArrayCreateMutableCopy(NULL, 0, watcherRefs);
} else {
newWatchers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
newWatcherRefs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
}
i = CFArrayGetFirstIndexOfValue(newWatchers,
CFRangeMake(0, CFArrayGetCount(newWatchers)),
sessionNum);
if (i == kCFNotFound) {
CFArrayAppendValue(newWatchers, sessionNum);
refCnt = 1;
refNum = CFNumberCreate(NULL, kCFNumberIntType, &refCnt);
CFArrayAppendValue(newWatcherRefs, refNum);
CFRelease(refNum);
} else {
refNum = CFArrayGetValueAtIndex(newWatcherRefs, i);
CFNumberGetValue(refNum, kCFNumberIntType, &refCnt);
refCnt++;
refNum = CFNumberCreate(NULL, kCFNumberIntType, &refCnt);
CFArraySetValueAtIndex(newWatcherRefs, i, refNum);
CFRelease(refNum);
}
CFDictionarySetValue(newDict, kSCDWatchers, newWatchers);
CFRelease(newWatchers);
CFDictionarySetValue(newDict, kSCDWatcherRefs, newWatcherRefs);
CFRelease(newWatcherRefs);
CFDictionarySetValue(storeData, watchedKey, newDict);
CFRelease(newDict);
#ifdef DEBUG
SC_log(LOG_DEBUG, " _addWatcher: %@, %@", sessionNum, watchedKey);
#endif
return;
}
__private_extern__
void
_removeWatcher(CFNumberRef sessionNum, CFStringRef watchedKey)
{
CFDictionaryRef dict;
CFMutableDictionaryRef newDict;
CFArrayRef watchers;
CFMutableArrayRef newWatchers;
CFArrayRef watcherRefs;
CFMutableArrayRef newWatcherRefs;
CFIndex i;
int refCnt;
CFNumberRef refNum;
dict = CFDictionaryGetValue(storeData, watchedKey);
if ((dict == NULL) || !CFDictionaryContainsKey(dict, kSCDWatchers)) {
#ifdef DEBUG
SC_log(LOG_DEBUG, " _removeWatcher: %@, %@, key not watched", sessionNum, watchedKey);
#endif
return;
}
newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
watchers = CFDictionaryGetValue(newDict, kSCDWatchers);
newWatchers = CFArrayCreateMutableCopy(NULL, 0, watchers);
watcherRefs = CFDictionaryGetValue(newDict, kSCDWatcherRefs);
newWatcherRefs = CFArrayCreateMutableCopy(NULL, 0, watcherRefs);
i = CFArrayGetFirstIndexOfValue(newWatchers,
CFRangeMake(0, CFArrayGetCount(newWatchers)),
sessionNum);
if (i == kCFNotFound) {
#ifdef DEBUG
SC_log(LOG_DEBUG, " _removeWatcher: %@, %@, session not watching", sessionNum, watchedKey);
#endif
CFRelease(newDict);
CFRelease(newWatchers);
CFRelease(newWatcherRefs);
return;
}
refNum = CFArrayGetValueAtIndex(newWatcherRefs, i);
CFNumberGetValue(refNum, kCFNumberIntType, &refCnt);
if (--refCnt > 0) {
refNum = CFNumberCreate(NULL, kCFNumberIntType, &refCnt);
CFArraySetValueAtIndex(newWatcherRefs, i, refNum);
CFRelease(refNum);
} else {
CFArrayRemoveValueAtIndex(newWatchers, i);
CFArrayRemoveValueAtIndex(newWatcherRefs, i);
}
if (CFArrayGetCount(newWatchers) > 0) {
CFDictionarySetValue(newDict, kSCDWatchers, newWatchers);
CFDictionarySetValue(newDict, kSCDWatcherRefs, newWatcherRefs);
} else {
CFDictionaryRemoveValue(newDict, kSCDWatchers);
CFDictionaryRemoveValue(newDict, kSCDWatcherRefs);
}
CFRelease(newWatchers);
CFRelease(newWatcherRefs);
if (CFDictionaryGetCount(newDict) > 0) {
CFDictionarySetValue(storeData, watchedKey, newDict);
} else {
CFDictionaryRemoveValue(storeData, watchedKey);
}
CFRelease(newDict);
#ifdef DEBUG
SC_log(LOG_DEBUG, " _removeWatcher: %@, %@", sessionNum, watchedKey);
#endif
return;
}
#define N_QUICK 64
__private_extern__
void
pushNotifications(void)
{
CFIndex notifyCnt;
int server;
const void * sessionsToNotify_q[N_QUICK];
const void ** sessionsToNotify = sessionsToNotify_q;
SCDynamicStorePrivateRef storePrivate;
serverSessionRef theSession;
if (needsNotification == NULL)
return;
notifyCnt = CFSetGetCount(needsNotification);
if (notifyCnt > (CFIndex)(sizeof(sessionsToNotify_q) / sizeof(CFNumberRef)))
sessionsToNotify = CFAllocatorAllocate(NULL, notifyCnt * sizeof(CFNumberRef), 0);
CFSetGetValues(needsNotification, sessionsToNotify);
while (--notifyCnt >= 0) {
(void) CFNumberGetValue(sessionsToNotify[notifyCnt],
kCFNumberIntType,
&server);
theSession = getSession(server);
assert(theSession != NULL);
storePrivate = (SCDynamicStorePrivateRef)theSession->store;
if ((storePrivate->notifyStatus == Using_NotifierInformViaMachPort) &&
(storePrivate->notifyPort != MACH_PORT_NULL)) {
SC_trace("-->port : %5d : port = %d",
storePrivate->server,
storePrivate->notifyPort);
while (storePrivate->notifyPortIdentifier == 0) {
storePrivate->notifyPortIdentifier = (mach_msg_id_t)random();
}
_SC_sendMachMessage(storePrivate->notifyPort, storePrivate->notifyPortIdentifier);
}
if ((storePrivate->notifyStatus == Using_NotifierInformViaFD) &&
(storePrivate->notifyFile >= 0)) {
ssize_t written;
SC_trace("-->fd : %5d : fd = %d, msgid = %d",
storePrivate->server,
storePrivate->notifyFile,
storePrivate->notifyFileIdentifier);
written = write(storePrivate->notifyFile,
&storePrivate->notifyFileIdentifier,
sizeof(storePrivate->notifyFileIdentifier));
if (written == -1) {
if (errno == EWOULDBLOCK) {
#ifdef DEBUG
SC_log(LOG_DEBUG, "sorry, only one outstanding notification per session");
#endif
} else {
#ifdef DEBUG
SC_log(LOG_DEBUG, "could not send notification, write() failed: %s",
strerror(errno));
#endif
storePrivate->notifyFile = -1;
}
} else if (written != sizeof(storePrivate->notifyFileIdentifier)) {
#ifdef DEBUG
SC_log(LOG_DEBUG, "could not send notification, incomplete write()");
#endif
storePrivate->notifyFile = -1;
}
}
}
if (sessionsToNotify != sessionsToNotify_q) CFAllocatorDeallocate(NULL, sessionsToNotify);
CFRelease(needsNotification);
needsNotification = NULL;
return;
}