]> git.saurik.com Git - apple/configd.git/blob - configd.tproj/_SCD.c
configd-1061.40.2.tar.gz
[apple/configd.git] / configd.tproj / _SCD.c
1 /*
2 * Copyright (c) 2000, 2001, 2003-2005, 2009, 2011, 2012, 2015-2019 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 storeData = NULL;
43
44 __private_extern__ CFMutableDictionaryRef patternData = NULL;
45
46 __private_extern__ CFMutableSetRef changedKeys = NULL;
47
48 __private_extern__ CFMutableSetRef deferredRemovals = NULL;
49
50 __private_extern__ CFMutableSetRef removedSessionKeys = NULL;
51
52 __private_extern__ CFMutableSetRef needsNotification = NULL;
53
54
55 __private_extern__
56 void
57 _addWatcher(CFNumberRef sessionNum, CFStringRef watchedKey)
58 {
59 CFDictionaryRef dict;
60 CFMutableDictionaryRef newDict;
61 CFArrayRef watchers;
62 CFMutableArrayRef newWatchers;
63 CFArrayRef watcherRefs;
64 CFMutableArrayRef newWatcherRefs;
65 CFIndex i;
66 int refCnt;
67 CFNumberRef refNum;
68
69 /*
70 * Get the dictionary associated with this key out of the store
71 */
72 dict = CFDictionaryGetValue(storeData, watchedKey);
73 if (dict != NULL) {
74 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
75 } else {
76 newDict = CFDictionaryCreateMutable(NULL,
77 0,
78 &kCFTypeDictionaryKeyCallBacks,
79 &kCFTypeDictionaryValueCallBacks);
80 }
81
82 /*
83 * Get the set of watchers out of the keys dictionary
84 */
85 watchers = CFDictionaryGetValue(newDict, kSCDWatchers);
86 watcherRefs = CFDictionaryGetValue(newDict, kSCDWatcherRefs);
87 if (watchers) {
88 newWatchers = CFArrayCreateMutableCopy(NULL, 0, watchers);
89 newWatcherRefs = CFArrayCreateMutableCopy(NULL, 0, watcherRefs);
90 } else {
91 newWatchers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
92 newWatcherRefs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
93 }
94
95 /*
96 * Add my session to the set of watchers
97 */
98 i = CFArrayGetFirstIndexOfValue(newWatchers,
99 CFRangeMake(0, CFArrayGetCount(newWatchers)),
100 sessionNum);
101 if (i == kCFNotFound) {
102 /* if this is the first instance of this session watching this key */
103 CFArrayAppendValue(newWatchers, sessionNum);
104 refCnt = 1;
105 refNum = CFNumberCreate(NULL, kCFNumberIntType, &refCnt);
106 CFArrayAppendValue(newWatcherRefs, refNum);
107 CFRelease(refNum);
108 } else {
109 /* if this is another instance of this session watching this key */
110 refNum = CFArrayGetValueAtIndex(newWatcherRefs, i);
111 CFNumberGetValue(refNum, kCFNumberIntType, &refCnt);
112 refCnt++;
113 refNum = CFNumberCreate(NULL, kCFNumberIntType, &refCnt);
114 CFArraySetValueAtIndex(newWatcherRefs, i, refNum);
115 CFRelease(refNum);
116 }
117
118 /*
119 * Update the keys dictionary
120 */
121 CFDictionarySetValue(newDict, kSCDWatchers, newWatchers);
122 CFRelease(newWatchers);
123 CFDictionarySetValue(newDict, kSCDWatcherRefs, newWatcherRefs);
124 CFRelease(newWatcherRefs);
125
126 /*
127 * Update the store for this key
128 */
129 CFDictionarySetValue(storeData, watchedKey, newDict);
130 CFRelease(newDict);
131
132 #ifdef DEBUG
133 SC_log(LOG_DEBUG, " _addWatcher: %@, %@", sessionNum, watchedKey);
134 #endif /* DEBUG */
135
136 return;
137 }
138
139
140 __private_extern__
141 void
142 _removeWatcher(CFNumberRef sessionNum, CFStringRef watchedKey)
143 {
144 CFDictionaryRef dict;
145 CFMutableDictionaryRef newDict;
146 CFArrayRef watchers;
147 CFMutableArrayRef newWatchers;
148 CFArrayRef watcherRefs;
149 CFMutableArrayRef newWatcherRefs;
150 CFIndex i;
151 int refCnt;
152 CFNumberRef refNum;
153
154 /*
155 * Get the dictionary associated with this key out of the store
156 */
157 dict = CFDictionaryGetValue(storeData, watchedKey);
158 if ((dict == NULL) || !CFDictionaryContainsKey(dict, kSCDWatchers)) {
159 /* key doesn't exist (isn't this really fatal?) */
160 #ifdef DEBUG
161 SC_log(LOG_DEBUG, " _removeWatcher: %@, %@, key not watched", sessionNum, watchedKey);
162 #endif /* DEBUG */
163 return;
164 }
165 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
166
167 /*
168 * Get the set of watchers out of the keys dictionary and
169 * remove this session from the list.
170 */
171 watchers = CFDictionaryGetValue(newDict, kSCDWatchers);
172 newWatchers = CFArrayCreateMutableCopy(NULL, 0, watchers);
173
174 watcherRefs = CFDictionaryGetValue(newDict, kSCDWatcherRefs);
175 newWatcherRefs = CFArrayCreateMutableCopy(NULL, 0, watcherRefs);
176
177 /* locate the session reference */
178 i = CFArrayGetFirstIndexOfValue(newWatchers,
179 CFRangeMake(0, CFArrayGetCount(newWatchers)),
180 sessionNum);
181 if (i == kCFNotFound) {
182 #ifdef DEBUG
183 SC_log(LOG_DEBUG, " _removeWatcher: %@, %@, session not watching", sessionNum, watchedKey);
184 #endif /* DEBUG */
185 CFRelease(newDict);
186 CFRelease(newWatchers);
187 CFRelease(newWatcherRefs);
188 return;
189 }
190
191 /* remove one session reference */
192 refNum = CFArrayGetValueAtIndex(newWatcherRefs, i);
193 CFNumberGetValue(refNum, kCFNumberIntType, &refCnt);
194 if (--refCnt > 0) {
195 refNum = CFNumberCreate(NULL, kCFNumberIntType, &refCnt);
196 CFArraySetValueAtIndex(newWatcherRefs, i, refNum);
197 CFRelease(refNum);
198 } else {
199 /* if this was the last reference */
200 CFArrayRemoveValueAtIndex(newWatchers, i);
201 CFArrayRemoveValueAtIndex(newWatcherRefs, i);
202 }
203
204 if (CFArrayGetCount(newWatchers) > 0) {
205 /* if this key is still being "watched" */
206 CFDictionarySetValue(newDict, kSCDWatchers, newWatchers);
207 CFDictionarySetValue(newDict, kSCDWatcherRefs, newWatcherRefs);
208 } else {
209 /* no watchers left, remove the empty set */
210 CFDictionaryRemoveValue(newDict, kSCDWatchers);
211 CFDictionaryRemoveValue(newDict, kSCDWatcherRefs);
212 }
213 CFRelease(newWatchers);
214 CFRelease(newWatcherRefs);
215
216 if (CFDictionaryGetCount(newDict) > 0) {
217 /* if this key is still active */
218 CFDictionarySetValue(storeData, watchedKey, newDict);
219 } else {
220 /* no information left, remove the empty dictionary */
221 CFDictionaryRemoveValue(storeData, watchedKey);
222 }
223 CFRelease(newDict);
224
225 #ifdef DEBUG
226 SC_log(LOG_DEBUG, " _removeWatcher: %@, %@", sessionNum, watchedKey);
227 #endif /* DEBUG */
228
229 return;
230 }
231
232
233 #define N_QUICK 64
234
235
236 __private_extern__
237 void
238 pushNotifications(void)
239 {
240 CFIndex notifyCnt;
241 int server;
242 const void * sessionsToNotify_q[N_QUICK];
243 const void ** sessionsToNotify = sessionsToNotify_q;
244 SCDynamicStorePrivateRef storePrivate;
245 serverSessionRef theSession;
246
247 if (needsNotification == NULL)
248 return; /* if no sessions need to be kicked */
249
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],
256 kCFNumberIntType,
257 &server);
258 theSession = getSession(server);
259 assert(theSession != NULL);
260
261 storePrivate = (SCDynamicStorePrivateRef)theSession->store;
262
263 /*
264 * deliver [CFRunLoop/dispatch] notifications to client sessions
265 */
266 if ((storePrivate->notifyStatus == Using_NotifierInformViaMachPort) &&
267 (storePrivate->notifyPort != MACH_PORT_NULL)) {
268 /*
269 * Post notification as mach message
270 */
271 SC_trace("-->port : %5d : port = %d",
272 storePrivate->server,
273 storePrivate->notifyPort);
274
275 /* use a random (and non-zero) identifier */
276 while (storePrivate->notifyPortIdentifier == 0) {
277 storePrivate->notifyPortIdentifier = (mach_msg_id_t)random();
278 }
279
280 _SC_sendMachMessage(storePrivate->notifyPort, storePrivate->notifyPortIdentifier);
281 }
282
283 if ((storePrivate->notifyStatus == Using_NotifierInformViaFD) &&
284 (storePrivate->notifyFile >= 0)) {
285 ssize_t written;
286
287 SC_trace("-->fd : %5d : fd = %d, msgid = %d",
288 storePrivate->server,
289 storePrivate->notifyFile,
290 storePrivate->notifyFileIdentifier);
291
292 written = write(storePrivate->notifyFile,
293 &storePrivate->notifyFileIdentifier,
294 sizeof(storePrivate->notifyFileIdentifier));
295 if (written == -1) {
296 if (errno == EWOULDBLOCK) {
297 #ifdef DEBUG
298 SC_log(LOG_DEBUG, "sorry, only one outstanding notification per session");
299 #endif /* DEBUG */
300 } else {
301 #ifdef DEBUG
302 SC_log(LOG_DEBUG, "could not send notification, write() failed: %s",
303 strerror(errno));
304 #endif /* DEBUG */
305 storePrivate->notifyFile = -1;
306 }
307 } else if (written != sizeof(storePrivate->notifyFileIdentifier)) {
308 #ifdef DEBUG
309 SC_log(LOG_DEBUG, "could not send notification, incomplete write()");
310 #endif /* DEBUG */
311 storePrivate->notifyFile = -1;
312 }
313 }
314 }
315 if (sessionsToNotify != sessionsToNotify_q) CFAllocatorDeallocate(NULL, sessionsToNotify);
316
317 /*
318 * this list of notifications have been posted, wait for some more.
319 */
320 CFRelease(needsNotification);
321 needsNotification = NULL;
322
323 return;
324 }