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