2 * Copyright (c) 2000, 2001, 2003-2005, 2009, 2011, 2012 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 sessionData
= NULL
;
44 __private_extern__ CFMutableDictionaryRef storeData
= NULL
;
46 __private_extern__ CFMutableDictionaryRef patternData
= NULL
;
48 __private_extern__ CFMutableSetRef changedKeys
= NULL
;
50 __private_extern__ CFMutableSetRef deferredRemovals
= NULL
;
52 __private_extern__ CFMutableSetRef removedSessionKeys
= NULL
;
54 __private_extern__ CFMutableSetRef needsNotification
= NULL
;
59 _addWatcher(CFNumberRef sessionNum
, CFStringRef watchedKey
)
62 CFMutableDictionaryRef newDict
;
64 CFMutableArrayRef newWatchers
;
65 CFArrayRef watcherRefs
;
66 CFMutableArrayRef newWatcherRefs
;
72 * Get the dictionary associated with this key out of the store
74 dict
= CFDictionaryGetValue(storeData
, watchedKey
);
76 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
78 newDict
= CFDictionaryCreateMutable(NULL
,
80 &kCFTypeDictionaryKeyCallBacks
,
81 &kCFTypeDictionaryValueCallBacks
);
85 * Get the set of watchers out of the keys dictionary
87 watchers
= CFDictionaryGetValue(newDict
, kSCDWatchers
);
88 watcherRefs
= CFDictionaryGetValue(newDict
, kSCDWatcherRefs
);
90 newWatchers
= CFArrayCreateMutableCopy(NULL
, 0, watchers
);
91 newWatcherRefs
= CFArrayCreateMutableCopy(NULL
, 0, watcherRefs
);
93 newWatchers
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
94 newWatcherRefs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
98 * Add my session to the set of watchers
100 i
= CFArrayGetFirstIndexOfValue(newWatchers
,
101 CFRangeMake(0, CFArrayGetCount(newWatchers
)),
103 if (i
== kCFNotFound
) {
104 /* if this is the first instance of this session watching this key */
105 CFArrayAppendValue(newWatchers
, sessionNum
);
107 refNum
= CFNumberCreate(NULL
, kCFNumberIntType
, &refCnt
);
108 CFArrayAppendValue(newWatcherRefs
, refNum
);
111 /* if this is another instance of this session watching this key */
112 refNum
= CFArrayGetValueAtIndex(newWatcherRefs
, i
);
113 CFNumberGetValue(refNum
, kCFNumberIntType
, &refCnt
);
115 refNum
= CFNumberCreate(NULL
, kCFNumberIntType
, &refCnt
);
116 CFArraySetValueAtIndex(newWatcherRefs
, i
, refNum
);
121 * Update the keys dictionary
123 CFDictionarySetValue(newDict
, kSCDWatchers
, newWatchers
);
124 CFRelease(newWatchers
);
125 CFDictionarySetValue(newDict
, kSCDWatcherRefs
, newWatcherRefs
);
126 CFRelease(newWatcherRefs
);
129 * Update the store for this key
131 CFDictionarySetValue(storeData
, watchedKey
, newDict
);
135 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR(" _addWatcher: %@, %@"), sessionNum
, watchedKey
);
144 _removeWatcher(CFNumberRef sessionNum
, CFStringRef watchedKey
)
146 CFDictionaryRef dict
;
147 CFMutableDictionaryRef newDict
;
149 CFMutableArrayRef newWatchers
;
150 CFArrayRef watcherRefs
;
151 CFMutableArrayRef newWatcherRefs
;
157 * Get the dictionary associated with this key out of the store
159 dict
= CFDictionaryGetValue(storeData
, watchedKey
);
160 if ((dict
== NULL
) || (CFDictionaryContainsKey(dict
, kSCDWatchers
) == FALSE
)) {
161 /* key doesn't exist (isn't this really fatal?) */
163 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR(" _removeWatcher: %@, %@, key not watched"), sessionNum
, watchedKey
);
167 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
170 * Get the set of watchers out of the keys dictionary and
171 * remove this session from the list.
173 watchers
= CFDictionaryGetValue(newDict
, kSCDWatchers
);
174 newWatchers
= CFArrayCreateMutableCopy(NULL
, 0, watchers
);
176 watcherRefs
= CFDictionaryGetValue(newDict
, kSCDWatcherRefs
);
177 newWatcherRefs
= CFArrayCreateMutableCopy(NULL
, 0, watcherRefs
);
179 /* locate the session reference */
180 i
= CFArrayGetFirstIndexOfValue(newWatchers
,
181 CFRangeMake(0, CFArrayGetCount(newWatchers
)),
183 if (i
== kCFNotFound
) {
185 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR(" _removeWatcher: %@, %@, session not watching"), sessionNum
, watchedKey
);
188 CFRelease(newWatchers
);
189 CFRelease(newWatcherRefs
);
193 /* remove one session reference */
194 refNum
= CFArrayGetValueAtIndex(newWatcherRefs
, i
);
195 CFNumberGetValue(refNum
, kCFNumberIntType
, &refCnt
);
197 refNum
= CFNumberCreate(NULL
, kCFNumberIntType
, &refCnt
);
198 CFArraySetValueAtIndex(newWatcherRefs
, i
, refNum
);
201 /* if this was the last reference */
202 CFArrayRemoveValueAtIndex(newWatchers
, i
);
203 CFArrayRemoveValueAtIndex(newWatcherRefs
, i
);
206 if (CFArrayGetCount(newWatchers
) > 0) {
207 /* if this key is still being "watched" */
208 CFDictionarySetValue(newDict
, kSCDWatchers
, newWatchers
);
209 CFDictionarySetValue(newDict
, kSCDWatcherRefs
, newWatcherRefs
);
211 /* no watchers left, remove the empty set */
212 CFDictionaryRemoveValue(newDict
, kSCDWatchers
);
213 CFDictionaryRemoveValue(newDict
, kSCDWatcherRefs
);
215 CFRelease(newWatchers
);
216 CFRelease(newWatcherRefs
);
218 if (CFDictionaryGetCount(newDict
) > 0) {
219 /* if this key is still active */
220 CFDictionarySetValue(storeData
, watchedKey
, newDict
);
222 /* no information left, remove the empty dictionary */
223 CFDictionaryRemoveValue(storeData
, watchedKey
);
228 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR(" _removeWatcher: %@, %@"), sessionNum
, watchedKey
);
240 pushNotifications(FILE *_configd_trace
)
244 const void * sessionsToNotify_q
[N_QUICK
];
245 const void ** sessionsToNotify
= sessionsToNotify_q
;
246 SCDynamicStorePrivateRef storePrivate
;
247 serverSessionRef theSession
;
249 if (needsNotification
== NULL
)
250 return; /* if no sessions need to be kicked */
252 notifyCnt
= CFSetGetCount(needsNotification
);
253 if (notifyCnt
> (CFIndex
)(sizeof(sessionsToNotify_q
) / sizeof(CFNumberRef
)))
254 sessionsToNotify
= CFAllocatorAllocate(NULL
, notifyCnt
* sizeof(CFNumberRef
), 0);
255 CFSetGetValues(needsNotification
, sessionsToNotify
);
256 while (--notifyCnt
>= 0) {
257 (void) CFNumberGetValue(sessionsToNotify
[notifyCnt
],
260 theSession
= getSession(server
);
261 storePrivate
= (SCDynamicStorePrivateRef
)theSession
->store
;
264 * deliver notifications to client sessions
266 if ((storePrivate
->notifyStatus
== Using_NotifierInformViaMachPort
) &&
267 (storePrivate
->notifyPort
!= MACH_PORT_NULL
)) {
269 * Post notification as mach message
271 if (_configd_trace
!= NULL
) {
272 SCTrace(TRUE
, _configd_trace
,
273 CFSTR("%s : %5d : port = %d, msgid = %d\n"),
275 storePrivate
->server
,
276 storePrivate
->notifyPort
,
277 storePrivate
->notifyPortIdentifier
);
280 _SC_sendMachMessage(storePrivate
->notifyPort
, storePrivate
->notifyPortIdentifier
);
283 if ((storePrivate
->notifyStatus
== Using_NotifierInformViaFD
) &&
284 (storePrivate
->notifyFile
>= 0)) {
287 if (_configd_trace
!= NULL
) {
288 SCTrace(TRUE
, _configd_trace
,
289 CFSTR("%s : %5d : fd = %d, msgid = %d\n"),
291 storePrivate
->server
,
292 storePrivate
->notifyFile
,
293 storePrivate
->notifyFileIdentifier
);
296 written
= write(storePrivate
->notifyFile
,
297 &storePrivate
->notifyFileIdentifier
,
298 sizeof(storePrivate
->notifyFileIdentifier
));
300 if (errno
== EWOULDBLOCK
) {
302 SCLog(_configd_verbose
, LOG_DEBUG
,
303 CFSTR("sorry, only one outstanding notification per session."));
307 SCLog(_configd_verbose
, LOG_DEBUG
,
308 CFSTR("could not send notification, write() failed: %s"),
311 storePrivate
->notifyFile
= -1;
313 } else if (written
!= sizeof(storePrivate
->notifyFileIdentifier
)) {
315 SCLog(_configd_verbose
, LOG_DEBUG
,
316 CFSTR("could not send notification, incomplete write()"));
318 storePrivate
->notifyFile
= -1;
322 if ((storePrivate
->notifyStatus
== Using_NotifierInformViaSignal
) &&
323 (storePrivate
->notifySignal
> 0)) {
324 kern_return_t status
;
327 * Post notification as signal
329 status
= pid_for_task(storePrivate
->notifySignalTask
, &pid
);
330 if (status
== KERN_SUCCESS
) {
331 if (_configd_trace
!= NULL
) {
332 SCTrace(TRUE
, _configd_trace
,
333 CFSTR("%s : %5d : pid = %d, signal = sig%s (%d)\n"),
335 storePrivate
->server
,
337 sys_signame
[storePrivate
->notifySignal
],
338 storePrivate
->notifySignal
);
341 if (kill(pid
, storePrivate
->notifySignal
) != 0) {
342 if (errno
!= ESRCH
) {
344 CFSTR("could not send sig%s to PID %d: %s"),
345 sys_signame
[storePrivate
->notifySignal
],
353 __MACH_PORT_DEBUG(TRUE
, "*** pushNotifications pid_for_task failed: releasing task", storePrivate
->notifySignalTask
);
354 if (mach_port_type(mach_task_self(), storePrivate
->notifySignalTask
, &pt
) == KERN_SUCCESS
) {
355 if ((pt
& MACH_PORT_TYPE_DEAD_NAME
) != 0) {
356 SCLog(TRUE
, LOG_ERR
, CFSTR("pushNotifications pid_for_task() failed: %s"), mach_error_string(status
));
359 SCLog(TRUE
, LOG_ERR
, CFSTR("pushNotifications mach_port_type() failed: %s"), mach_error_string(status
));
362 /* don't bother with any more attempts */
363 (void) mach_port_deallocate(mach_task_self(), storePrivate
->notifySignalTask
);
364 storePrivate
->notifySignal
= 0;
365 storePrivate
->notifySignalTask
= TASK_NULL
;
369 if (sessionsToNotify
!= sessionsToNotify_q
) CFAllocatorDeallocate(NULL
, sessionsToNotify
);
372 * this list of notifications have been posted, wait for some more.
374 CFRelease(needsNotification
);
375 needsNotification
= NULL
;