2 * Copyright (c) 2000, 2001, 2003-2005, 2009, 2011, 2012, 2015-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 * June 2, 2000 Allan Nathanson <ajn@apple.com>
38 #include "configd_server.h"
42 __private_extern__ CFMutableDictionaryRef storeData
= NULL
;
44 __private_extern__ CFMutableDictionaryRef patternData
= NULL
;
46 __private_extern__ CFMutableSetRef changedKeys
= NULL
;
48 __private_extern__ CFMutableSetRef deferredRemovals
= NULL
;
50 __private_extern__ CFMutableSetRef removedSessionKeys
= NULL
;
52 __private_extern__ CFMutableSetRef needsNotification
= NULL
;
57 _addWatcher(CFNumberRef sessionNum
, CFStringRef watchedKey
)
60 CFMutableDictionaryRef newDict
;
62 CFMutableArrayRef newWatchers
;
63 CFArrayRef watcherRefs
;
64 CFMutableArrayRef newWatcherRefs
;
70 * Get the dictionary associated with this key out of the store
72 dict
= CFDictionaryGetValue(storeData
, watchedKey
);
74 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
76 newDict
= CFDictionaryCreateMutable(NULL
,
78 &kCFTypeDictionaryKeyCallBacks
,
79 &kCFTypeDictionaryValueCallBacks
);
83 * Get the set of watchers out of the keys dictionary
85 watchers
= CFDictionaryGetValue(newDict
, kSCDWatchers
);
86 watcherRefs
= CFDictionaryGetValue(newDict
, kSCDWatcherRefs
);
88 newWatchers
= CFArrayCreateMutableCopy(NULL
, 0, watchers
);
89 newWatcherRefs
= CFArrayCreateMutableCopy(NULL
, 0, watcherRefs
);
91 newWatchers
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
92 newWatcherRefs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
96 * Add my session to the set of watchers
98 i
= CFArrayGetFirstIndexOfValue(newWatchers
,
99 CFRangeMake(0, CFArrayGetCount(newWatchers
)),
101 if (i
== kCFNotFound
) {
102 /* if this is the first instance of this session watching this key */
103 CFArrayAppendValue(newWatchers
, sessionNum
);
105 refNum
= CFNumberCreate(NULL
, kCFNumberIntType
, &refCnt
);
106 CFArrayAppendValue(newWatcherRefs
, refNum
);
109 /* if this is another instance of this session watching this key */
110 refNum
= CFArrayGetValueAtIndex(newWatcherRefs
, i
);
111 CFNumberGetValue(refNum
, kCFNumberIntType
, &refCnt
);
113 refNum
= CFNumberCreate(NULL
, kCFNumberIntType
, &refCnt
);
114 CFArraySetValueAtIndex(newWatcherRefs
, i
, refNum
);
119 * Update the keys dictionary
121 CFDictionarySetValue(newDict
, kSCDWatchers
, newWatchers
);
122 CFRelease(newWatchers
);
123 CFDictionarySetValue(newDict
, kSCDWatcherRefs
, newWatcherRefs
);
124 CFRelease(newWatcherRefs
);
127 * Update the store for this key
129 CFDictionarySetValue(storeData
, watchedKey
, newDict
);
133 SC_log(LOG_DEBUG
, " _addWatcher: %@, %@", sessionNum
, watchedKey
);
142 _removeWatcher(CFNumberRef sessionNum
, CFStringRef watchedKey
)
144 CFDictionaryRef dict
;
145 CFMutableDictionaryRef newDict
;
147 CFMutableArrayRef newWatchers
;
148 CFArrayRef watcherRefs
;
149 CFMutableArrayRef newWatcherRefs
;
155 * Get the dictionary associated with this key out of the store
157 dict
= CFDictionaryGetValue(storeData
, watchedKey
);
158 if ((dict
== NULL
) || !CFDictionaryContainsKey(dict
, kSCDWatchers
)) {
159 /* key doesn't exist (isn't this really fatal?) */
161 SC_log(LOG_DEBUG
, " _removeWatcher: %@, %@, key not watched", sessionNum
, watchedKey
);
165 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
168 * Get the set of watchers out of the keys dictionary and
169 * remove this session from the list.
171 watchers
= CFDictionaryGetValue(newDict
, kSCDWatchers
);
172 newWatchers
= CFArrayCreateMutableCopy(NULL
, 0, watchers
);
174 watcherRefs
= CFDictionaryGetValue(newDict
, kSCDWatcherRefs
);
175 newWatcherRefs
= CFArrayCreateMutableCopy(NULL
, 0, watcherRefs
);
177 /* locate the session reference */
178 i
= CFArrayGetFirstIndexOfValue(newWatchers
,
179 CFRangeMake(0, CFArrayGetCount(newWatchers
)),
181 if (i
== kCFNotFound
) {
183 SC_log(LOG_DEBUG
, " _removeWatcher: %@, %@, session not watching", sessionNum
, watchedKey
);
186 CFRelease(newWatchers
);
187 CFRelease(newWatcherRefs
);
191 /* remove one session reference */
192 refNum
= CFArrayGetValueAtIndex(newWatcherRefs
, i
);
193 CFNumberGetValue(refNum
, kCFNumberIntType
, &refCnt
);
195 refNum
= CFNumberCreate(NULL
, kCFNumberIntType
, &refCnt
);
196 CFArraySetValueAtIndex(newWatcherRefs
, i
, refNum
);
199 /* if this was the last reference */
200 CFArrayRemoveValueAtIndex(newWatchers
, i
);
201 CFArrayRemoveValueAtIndex(newWatcherRefs
, i
);
204 if (CFArrayGetCount(newWatchers
) > 0) {
205 /* if this key is still being "watched" */
206 CFDictionarySetValue(newDict
, kSCDWatchers
, newWatchers
);
207 CFDictionarySetValue(newDict
, kSCDWatcherRefs
, newWatcherRefs
);
209 /* no watchers left, remove the empty set */
210 CFDictionaryRemoveValue(newDict
, kSCDWatchers
);
211 CFDictionaryRemoveValue(newDict
, kSCDWatcherRefs
);
213 CFRelease(newWatchers
);
214 CFRelease(newWatcherRefs
);
216 if (CFDictionaryGetCount(newDict
) > 0) {
217 /* if this key is still active */
218 CFDictionarySetValue(storeData
, watchedKey
, newDict
);
220 /* no information left, remove the empty dictionary */
221 CFDictionaryRemoveValue(storeData
, watchedKey
);
226 SC_log(LOG_DEBUG
, " _removeWatcher: %@, %@", sessionNum
, watchedKey
);
238 pushNotifications(void)
242 const void * sessionsToNotify_q
[N_QUICK
];
243 const void ** sessionsToNotify
= sessionsToNotify_q
;
244 SCDynamicStorePrivateRef storePrivate
;
245 serverSessionRef theSession
;
247 if (needsNotification
== NULL
)
248 return; /* if no sessions need to be kicked */
250 notifyCnt
= CFSetGetCount(needsNotification
);
251 if (notifyCnt
> (CFIndex
)(sizeof(sessionsToNotify_q
) / sizeof(CFNumberRef
)))
252 sessionsToNotify
= CFAllocatorAllocate(NULL
, notifyCnt
* sizeof(CFNumberRef
), 0);
253 CFSetGetValues(needsNotification
, sessionsToNotify
);
254 while (--notifyCnt
>= 0) {
255 (void) CFNumberGetValue(sessionsToNotify
[notifyCnt
],
258 theSession
= getSession(server
);
259 assert(theSession
!= NULL
);
261 storePrivate
= (SCDynamicStorePrivateRef
)theSession
->store
;
264 * deliver [CFRunLoop/dispatch] notifications to client sessions
266 if ((storePrivate
->notifyStatus
== Using_NotifierInformViaMachPort
) &&
267 (storePrivate
->notifyPort
!= MACH_PORT_NULL
)) {
269 * Post notification as mach message
271 SC_trace("-->port : %5d : port = %d",
272 storePrivate
->server
,
273 storePrivate
->notifyPort
);
275 /* use a random (and non-zero) identifier */
276 while (storePrivate
->notifyPortIdentifier
== 0) {
277 storePrivate
->notifyPortIdentifier
= (mach_msg_id_t
)random();
280 _SC_sendMachMessage(storePrivate
->notifyPort
, storePrivate
->notifyPortIdentifier
);
283 if ((storePrivate
->notifyStatus
== Using_NotifierInformViaFD
) &&
284 (storePrivate
->notifyFile
>= 0)) {
287 SC_trace("-->fd : %5d : fd = %d, msgid = %d",
288 storePrivate
->server
,
289 storePrivate
->notifyFile
,
290 storePrivate
->notifyFileIdentifier
);
292 written
= write(storePrivate
->notifyFile
,
293 &storePrivate
->notifyFileIdentifier
,
294 sizeof(storePrivate
->notifyFileIdentifier
));
296 if (errno
== EWOULDBLOCK
) {
298 SC_log(LOG_DEBUG
, "sorry, only one outstanding notification per session");
302 SC_log(LOG_DEBUG
, "could not send notification, write() failed: %s",
305 storePrivate
->notifyFile
= -1;
307 } else if (written
!= sizeof(storePrivate
->notifyFileIdentifier
)) {
309 SC_log(LOG_DEBUG
, "could not send notification, incomplete write()");
311 storePrivate
->notifyFile
= -1;
315 if (sessionsToNotify
!= sessionsToNotify_q
) CFAllocatorDeallocate(NULL
, sessionsToNotify
);
318 * this list of notifications have been posted, wait for some more.
320 CFRelease(needsNotification
);
321 needsNotification
= NULL
;