]> git.saurik.com Git - apple/configd.git/blob - configd.tproj/_SCD.c
configd-289.tar.gz
[apple/configd.git] / configd.tproj / _SCD.c
1 /*
2 * Copyright (c) 2000, 2001, 2003-2005, 2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * June 1, 2001 Allan Nathanson <ajn@apple.com>
28 * - public API conversion
29 *
30 * June 2, 2000 Allan Nathanson <ajn@apple.com>
31 * - initial revision
32 */
33
34
35 #include <unistd.h>
36
37 #include "configd.h"
38 #include "configd_server.h"
39 #include "session.h"
40
41
42 __private_extern__ CFMutableDictionaryRef sessionData = NULL;
43
44 __private_extern__ CFMutableDictionaryRef storeData = NULL;
45 __private_extern__ CFMutableDictionaryRef storeData_s = NULL;
46
47 __private_extern__ CFMutableDictionaryRef patternData = NULL;
48 __private_extern__ CFMutableDictionaryRef patternData_s = NULL;
49
50 __private_extern__ CFMutableSetRef changedKeys = NULL;
51 __private_extern__ CFMutableSetRef changedKeys_s = NULL;
52
53 __private_extern__ CFMutableSetRef deferredRemovals = NULL;
54 __private_extern__ CFMutableSetRef deferredRemovals_s = NULL;
55
56 __private_extern__ CFMutableSetRef removedSessionKeys = NULL;
57 __private_extern__ CFMutableSetRef removedSessionKeys_s = NULL;
58
59 __private_extern__ CFMutableSetRef needsNotification = NULL;
60
61 __private_extern__ int storeLocked = 0; /* > 0 if dynamic store locked */
62
63
64 __private_extern__
65 void
66 _swapLockedStoreData()
67 {
68 void *temp;
69
70 temp = storeData;
71 storeData = storeData_s;
72 storeData_s = temp;
73
74 temp = patternData;
75 patternData = patternData_s;
76 patternData_s = temp;
77
78 temp = changedKeys;
79 changedKeys = changedKeys_s;
80 changedKeys_s = temp;
81
82 temp = deferredRemovals;
83 deferredRemovals = deferredRemovals_s;
84 deferredRemovals_s = temp;
85
86 temp = removedSessionKeys;
87 removedSessionKeys = removedSessionKeys_s;
88 removedSessionKeys_s = temp;
89
90 return;
91 }
92
93
94 __private_extern__
95 void
96 _addWatcher(CFNumberRef sessionNum, CFStringRef watchedKey)
97 {
98 CFDictionaryRef dict;
99 CFMutableDictionaryRef newDict;
100 CFArrayRef watchers;
101 CFMutableArrayRef newWatchers;
102 CFArrayRef watcherRefs;
103 CFMutableArrayRef newWatcherRefs;
104 CFIndex i;
105 int refCnt;
106 CFNumberRef refNum;
107
108 /*
109 * Get the dictionary associated with this key out of the store
110 */
111 dict = CFDictionaryGetValue(storeData, watchedKey);
112 if (dict) {
113 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
114 } else {
115 newDict = CFDictionaryCreateMutable(NULL,
116 0,
117 &kCFTypeDictionaryKeyCallBacks,
118 &kCFTypeDictionaryValueCallBacks);
119 }
120
121 /*
122 * Get the set of watchers out of the keys dictionary
123 */
124 watchers = CFDictionaryGetValue(newDict, kSCDWatchers);
125 watcherRefs = CFDictionaryGetValue(newDict, kSCDWatcherRefs);
126 if (watchers) {
127 newWatchers = CFArrayCreateMutableCopy(NULL, 0, watchers);
128 newWatcherRefs = CFArrayCreateMutableCopy(NULL, 0, watcherRefs);
129 } else {
130 newWatchers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
131 newWatcherRefs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
132 }
133
134 /*
135 * Add my session to the set of watchers
136 */
137 i = CFArrayGetFirstIndexOfValue(newWatchers,
138 CFRangeMake(0, CFArrayGetCount(newWatchers)),
139 sessionNum);
140 if (i == kCFNotFound) {
141 /* if this is the first instance of this session watching this key */
142 CFArrayAppendValue(newWatchers, sessionNum);
143 refCnt = 1;
144 refNum = CFNumberCreate(NULL, kCFNumberIntType, &refCnt);
145 CFArrayAppendValue(newWatcherRefs, refNum);
146 CFRelease(refNum);
147 } else {
148 /* if this is another instance of this session watching this key */
149 refNum = CFArrayGetValueAtIndex(newWatcherRefs, i);
150 CFNumberGetValue(refNum, kCFNumberIntType, &refCnt);
151 refCnt++;
152 refNum = CFNumberCreate(NULL, kCFNumberIntType, &refCnt);
153 CFArraySetValueAtIndex(newWatcherRefs, i, refNum);
154 CFRelease(refNum);
155 }
156
157 /*
158 * Update the keys dictionary
159 */
160 CFDictionarySetValue(newDict, kSCDWatchers, newWatchers);
161 CFRelease(newWatchers);
162 CFDictionarySetValue(newDict, kSCDWatcherRefs, newWatcherRefs);
163 CFRelease(newWatcherRefs);
164
165 /*
166 * Update the store for this key
167 */
168 CFDictionarySetValue(storeData, watchedKey, newDict);
169 CFRelease(newDict);
170
171 #ifdef DEBUG
172 SCLog(_configd_verbose, LOG_DEBUG, CFSTR(" _addWatcher: %@, %@"), sessionNum, watchedKey);
173 #endif /* DEBUG */
174
175 return;
176 }
177
178
179 __private_extern__
180 void
181 _removeWatcher(CFNumberRef sessionNum, CFStringRef watchedKey)
182 {
183 CFDictionaryRef dict;
184 CFMutableDictionaryRef newDict;
185 CFArrayRef watchers;
186 CFMutableArrayRef newWatchers;
187 CFArrayRef watcherRefs;
188 CFMutableArrayRef newWatcherRefs;
189 CFIndex i;
190 int refCnt;
191 CFNumberRef refNum;
192
193 /*
194 * Get the dictionary associated with this key out of the store
195 */
196 dict = CFDictionaryGetValue(storeData, watchedKey);
197 if ((dict == NULL) || (CFDictionaryContainsKey(dict, kSCDWatchers) == FALSE)) {
198 /* key doesn't exist (isn't this really fatal?) */
199 #ifdef DEBUG
200 SCLog(_configd_verbose, LOG_DEBUG, CFSTR(" _removeWatcher: %@, %@, key not watched"), sessionNum, watchedKey);
201 #endif /* DEBUG */
202 return;
203 }
204 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
205
206 /*
207 * Get the set of watchers out of the keys dictionary and
208 * remove this session from the list.
209 */
210 watchers = CFDictionaryGetValue(newDict, kSCDWatchers);
211 newWatchers = CFArrayCreateMutableCopy(NULL, 0, watchers);
212
213 watcherRefs = CFDictionaryGetValue(newDict, kSCDWatcherRefs);
214 newWatcherRefs = CFArrayCreateMutableCopy(NULL, 0, watcherRefs);
215
216 /* locate the session reference */
217 i = CFArrayGetFirstIndexOfValue(newWatchers,
218 CFRangeMake(0, CFArrayGetCount(newWatchers)),
219 sessionNum);
220 if (i == kCFNotFound) {
221 #ifdef DEBUG
222 SCLog(_configd_verbose, LOG_DEBUG, CFSTR(" _removeWatcher: %@, %@, session not watching"), sessionNum, watchedKey);
223 #endif /* DEBUG */
224 CFRelease(newDict);
225 CFRelease(newWatchers);
226 CFRelease(newWatcherRefs);
227 return;
228 }
229
230 /* remove one session reference */
231 refNum = CFArrayGetValueAtIndex(newWatcherRefs, i);
232 CFNumberGetValue(refNum, kCFNumberIntType, &refCnt);
233 if (--refCnt > 0) {
234 refNum = CFNumberCreate(NULL, kCFNumberIntType, &refCnt);
235 CFArraySetValueAtIndex(newWatcherRefs, i, refNum);
236 CFRelease(refNum);
237 } else {
238 /* if this was the last reference */
239 CFArrayRemoveValueAtIndex(newWatchers, i);
240 CFArrayRemoveValueAtIndex(newWatcherRefs, i);
241 }
242
243 if (CFArrayGetCount(newWatchers) > 0) {
244 /* if this key is still being "watched" */
245 CFDictionarySetValue(newDict, kSCDWatchers, newWatchers);
246 CFDictionarySetValue(newDict, kSCDWatcherRefs, newWatcherRefs);
247 } else {
248 /* no watchers left, remove the empty set */
249 CFDictionaryRemoveValue(newDict, kSCDWatchers);
250 CFDictionaryRemoveValue(newDict, kSCDWatcherRefs);
251 }
252 CFRelease(newWatchers);
253 CFRelease(newWatcherRefs);
254
255 if (CFDictionaryGetCount(newDict) > 0) {
256 /* if this key is still active */
257 CFDictionarySetValue(storeData, watchedKey, newDict);
258 } else {
259 /* no information left, remove the empty dictionary */
260 CFDictionaryRemoveValue(storeData, watchedKey);
261 }
262 CFRelease(newDict);
263
264 #ifdef DEBUG
265 SCLog(_configd_verbose, LOG_DEBUG, CFSTR(" _removeWatcher: %@, %@"), sessionNum, watchedKey);
266 #endif /* DEBUG */
267
268 return;
269 }
270
271
272 __private_extern__
273 void
274 pushNotifications(FILE *_configd_trace)
275 {
276 const void **sessionsToNotify;
277 CFIndex notifyCnt;
278 int server;
279 serverSessionRef theSession;
280 SCDynamicStorePrivateRef storePrivate;
281
282 if (needsNotification == NULL)
283 return; /* if no sessions need to be kicked */
284
285 notifyCnt = CFSetGetCount(needsNotification);
286 sessionsToNotify = malloc(notifyCnt * sizeof(CFNumberRef));
287 CFSetGetValues(needsNotification, sessionsToNotify);
288 while (--notifyCnt >= 0) {
289 (void) CFNumberGetValue(sessionsToNotify[notifyCnt],
290 kCFNumberIntType,
291 &server);
292 theSession = getSession(server);
293 storePrivate = (SCDynamicStorePrivateRef)theSession->store;
294
295 /*
296 * deliver notifications to client sessions
297 */
298 if ((storePrivate->notifyStatus == Using_NotifierInformViaMachPort) &&
299 (storePrivate->notifyPort != MACH_PORT_NULL)) {
300 /*
301 * Post notification as mach message
302 */
303 if (_configd_trace != NULL) {
304 SCTrace(TRUE, _configd_trace,
305 CFSTR("%s : %5d : port = %d, msgid = %d\n"),
306 "-->port",
307 storePrivate->server,
308 storePrivate->notifyPort,
309 storePrivate->notifyPortIdentifier);
310 }
311
312 _SC_sendMachMessage(storePrivate->notifyPort, storePrivate->notifyPortIdentifier);
313 }
314
315 if ((storePrivate->notifyStatus == Using_NotifierInformViaFD) &&
316 (storePrivate->notifyFile >= 0)) {
317 ssize_t written;
318
319 if (_configd_trace != NULL) {
320 SCTrace(TRUE, _configd_trace,
321 CFSTR("%s : %5d : fd = %d, msgid = %d\n"),
322 "-->fd ",
323 storePrivate->server,
324 storePrivate->notifyFile,
325 storePrivate->notifyFileIdentifier);
326 }
327
328 written = write(storePrivate->notifyFile,
329 &storePrivate->notifyFileIdentifier,
330 sizeof(storePrivate->notifyFileIdentifier));
331 if (written == -1) {
332 if (errno == EWOULDBLOCK) {
333 #ifdef DEBUG
334 SCLog(_configd_verbose, LOG_DEBUG,
335 CFSTR("sorry, only one outstanding notification per session."));
336 #endif /* DEBUG */
337 } else {
338 #ifdef DEBUG
339 SCLog(_configd_verbose, LOG_DEBUG,
340 CFSTR("could not send notification, write() failed: %s"),
341 strerror(errno));
342 #endif /* DEBUG */
343 storePrivate->notifyFile = -1;
344 }
345 } else if (written != sizeof(storePrivate->notifyFileIdentifier)) {
346 #ifdef DEBUG
347 SCLog(_configd_verbose, LOG_DEBUG,
348 CFSTR("could not send notification, incomplete write()"));
349 #endif /* DEBUG */
350 storePrivate->notifyFile = -1;
351 }
352 }
353
354 if ((storePrivate->notifyStatus == Using_NotifierInformViaSignal) &&
355 (storePrivate->notifySignal > 0)) {
356 kern_return_t status;
357 pid_t pid;
358 /*
359 * Post notification as signal
360 */
361 status = pid_for_task(storePrivate->notifySignalTask, &pid);
362 if (status == KERN_SUCCESS) {
363 if (_configd_trace != NULL) {
364 SCTrace(TRUE, _configd_trace,
365 CFSTR("%s : %5d : pid = %d, signal = sig%s (%d)\n"),
366 "-->sig ",
367 storePrivate->server,
368 pid,
369 sys_signame[storePrivate->notifySignal],
370 storePrivate->notifySignal);
371 }
372
373 if (kill(pid, storePrivate->notifySignal) != 0) {
374 if (errno != ESRCH) {
375 SCLog(TRUE, LOG_ERR,
376 CFSTR("could not send sig%s to PID %d: %s"),
377 sys_signame[storePrivate->notifySignal],
378 pid,
379 strerror(errno));
380 }
381 }
382 } else {
383 mach_port_type_t pt;
384
385 __MACH_PORT_DEBUG(TRUE, "*** pushNotifications pid_for_task failed: releasing task", storePrivate->notifySignalTask);
386 if (mach_port_type(mach_task_self(), storePrivate->notifySignalTask, &pt) == KERN_SUCCESS) {
387 if ((pt & MACH_PORT_TYPE_DEAD_NAME) != 0) {
388 SCLog(TRUE, LOG_ERR, CFSTR("pushNotifications pid_for_task() failed: %s"), mach_error_string(status));
389 }
390 } else {
391 SCLog(TRUE, LOG_ERR, CFSTR("pushNotifications mach_port_type() failed: %s"), mach_error_string(status));
392 }
393
394 /* don't bother with any more attempts */
395 (void) mach_port_deallocate(mach_task_self(), storePrivate->notifySignalTask);
396 storePrivate->notifySignal = 0;
397 storePrivate->notifySignalTask = TASK_NULL;
398 }
399 }
400 }
401 free(sessionsToNotify);
402
403 /*
404 * this list of notifications have been posted, wait for some more.
405 */
406 CFRelease(needsNotification);
407 needsNotification = NULL;
408
409 return;
410 }