2 * Copyright (c) 2000-2004, 2006, 2011, 2015, 2017, 2019 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * June 1, 2001 Allan Nathanson <ajn@apple.com>
28 * - public API conversion
30 * March 24, 2000 Allan Nathanson <ajn@apple.com>
36 #include "configd_server.h"
48 const void * keys_q
[N_QUICK
];
49 const void ** keys
= keys_q
;
51 keyCnt
= CFSetGetCount(changedKeys
);
53 return; /* if nothing to do */
55 if (keyCnt
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFStringRef
)))
56 keys
= CFAllocatorAllocate(NULL
, keyCnt
* sizeof(CFStringRef
), 0);
58 CFSetGetValues(changedKeys
, keys
);
60 while (--keyCnt
>= 0) {
61 CFStringRef changedKey
= (CFStringRef
)keys
[keyCnt
];
63 CFArrayRef sessionsWatchingKey
;
65 const void * watchers_q
[N_QUICK
];
66 const void ** watchers
= watchers_q
;
68 dict
= CFDictionaryGetValue(storeData
, changedKey
);
69 if ((dict
== NULL
) || !CFDictionaryContainsKey(dict
, kSCDWatchers
)) {
70 /* key doesn't exist or nobody cares if it changed */
75 * Add this key to the list of changes for each of the
76 * sessions which is "watching".
78 sessionsWatchingKey
= CFDictionaryGetValue(dict
, kSCDWatchers
);
79 watcherCnt
= CFArrayGetCount(sessionsWatchingKey
);
80 if (watcherCnt
== 0) {
85 if (watcherCnt
> (CFIndex
)(sizeof(watchers_q
) / sizeof(CFNumberRef
)))
86 watchers
= CFAllocatorAllocate(NULL
, watcherCnt
* sizeof(CFNumberRef
), 0);
88 CFArrayGetValues(sessionsWatchingKey
, CFRangeMake(0, watcherCnt
), watchers
);
90 while (--watcherCnt
>= 0) {
91 serverSessionRef session
;
92 CFNumberRef watchedSession
= watchers
[watcherCnt
];
94 session
= getSessionNum(watchedSession
);
95 if (session
->changedKeys
== NULL
) {
96 session
->changedKeys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
98 if (!CFArrayContainsValue(session
->changedKeys
,
99 CFRangeMake(0, CFArrayGetCount(session
->changedKeys
)),
101 CFArrayAppendValue(session
->changedKeys
, changedKey
);
105 * flag this session as needing a kick
107 if (needsNotification
== NULL
)
108 needsNotification
= CFSetCreateMutable(NULL
,
110 &kCFTypeSetCallBacks
);
111 CFSetAddValue(needsNotification
, watchedSession
);
114 if (watchers
!= watchers_q
) CFAllocatorDeallocate(NULL
, watchers
);
117 if (keys
!= keys_q
) CFAllocatorDeallocate(NULL
, keys
);
120 * The list of changed keys have been updated for any sessions
121 * monitoring changes to the "store". The next step, handled by
122 * the "configd" server, is to push out any needed notifications.
124 CFSetRemoveAllValues(changedKeys
);
130 _processDeferredRemovals()
133 const void * keys_q
[N_QUICK
];
134 const void ** keys
= keys_q
;
136 keyCnt
= CFSetGetCount(deferredRemovals
);
138 return; /* if nothing to do */
140 if (keyCnt
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFStringRef
)))
141 keys
= CFAllocatorAllocate(NULL
, keyCnt
* sizeof(CFStringRef
), 0);
143 CFSetGetValues(deferredRemovals
, keys
);
145 while (--keyCnt
>= 0) {
146 patternRemoveKey((CFStringRef
)keys
[keyCnt
]);
149 if (keys
!= keys_q
) CFAllocatorDeallocate(NULL
, keys
);
152 * All regex keys associated with removed store dictionary keys have
153 * been removed. Start the list fresh again.
155 CFSetRemoveAllValues(deferredRemovals
);
162 _cleanupRemovedSessionKeys(const void *value
, void *context
)
164 #pragma unused(context)
165 CFStringRef removedKey
= (CFStringRef
)value
;
167 serverSessionRef session
;
168 CFStringRef sessionKey
;
172 dRange
= CFStringFind(removedKey
, CFSTR(":"), 0);
173 sessionKey
= CFStringCreateWithSubstring(NULL
,
175 CFRangeMake(0, dRange
.location
));
176 key
= CFStringCreateWithSubstring(NULL
,
178 CFRangeMake(dRange
.location
+dRange
.length
,
179 CFStringGetLength(removedKey
)-dRange
.location
-dRange
.length
));
181 session
= getSessionStr(sessionKey
);
182 if (session
== NULL
) {
187 i
= CFArrayGetFirstIndexOfValue(session
->sessionKeys
,
188 CFRangeMake(0, CFArrayGetCount(session
->sessionKeys
)),
190 if (i
== kCFNotFound
) {
191 /* if this session key has already been removed */
194 CFArrayRemoveValueAtIndex(session
->sessionKeys
, i
);
195 if (CFArrayGetCount(session
->sessionKeys
) == 0) {
196 CFRelease(session
->sessionKeys
);
197 session
->sessionKeys
= NULL
;
202 CFRelease(sessionKey
);
211 __SCDynamicStorePush(void)
214 * push notifications to any session watching those keys which
215 * were recently changed.
220 * process any deferred key deletions.
222 _processDeferredRemovals();
225 * clean up any removed session keys
227 CFSetApplyFunction(removedSessionKeys
, _cleanupRemovedSessionKeys
, NULL
);
228 CFSetRemoveAllValues(removedSessionKeys
);