]>
Commit | Line | Data |
---|---|---|
5958d7c0 | 1 | /* |
afb19109 | 2 | * Copyright (c) 2000, 2001, 2003-2005, 2009, 2011, 2012, 2015-2019 Apple Inc. All rights reserved. |
5958d7c0 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
9de8ab86 | 5 | * |
009ee3c6 A |
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. | |
9de8ab86 | 12 | * |
009ee3c6 A |
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 | |
5958d7c0 A |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
009ee3c6 A |
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. | |
9de8ab86 | 20 | * |
5958d7c0 A |
21 | * @APPLE_LICENSE_HEADER_END@ |
22 | */ | |
23 | ||
0fae82ee A |
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 | ||
5958d7c0 | 34 | |
dbf6a266 A |
35 | #include <unistd.h> |
36 | ||
5958d7c0 | 37 | #include "configd.h" |
dbf6a266 A |
38 | #include "configd_server.h" |
39 | #include "session.h" | |
5958d7c0 A |
40 | |
41 | ||
009ee3c6 | 42 | __private_extern__ CFMutableDictionaryRef storeData = NULL; |
5958d7c0 | 43 | |
009ee3c6 | 44 | __private_extern__ CFMutableDictionaryRef patternData = NULL; |
5958d7c0 | 45 | |
009ee3c6 | 46 | __private_extern__ CFMutableSetRef changedKeys = NULL; |
5958d7c0 | 47 | |
009ee3c6 | 48 | __private_extern__ CFMutableSetRef deferredRemovals = NULL; |
5958d7c0 | 49 | |
009ee3c6 | 50 | __private_extern__ CFMutableSetRef removedSessionKeys = NULL; |
5958d7c0 | 51 | |
009ee3c6 | 52 | __private_extern__ CFMutableSetRef needsNotification = NULL; |
5958d7c0 | 53 | |
5958d7c0 | 54 | |
009ee3c6 | 55 | __private_extern__ |
5958d7c0 A |
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 | /* | |
0fae82ee | 70 | * Get the dictionary associated with this key out of the store |
5958d7c0 | 71 | */ |
0fae82ee | 72 | dict = CFDictionaryGetValue(storeData, watchedKey); |
942cecd7 | 73 | if (dict != NULL) { |
5958d7c0 A |
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); | |
dbf6a266 | 101 | if (i == kCFNotFound) { |
5958d7c0 A |
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 | /* | |
0fae82ee | 127 | * Update the store for this key |
5958d7c0 | 128 | */ |
0fae82ee | 129 | CFDictionarySetValue(storeData, watchedKey, newDict); |
5958d7c0 A |
130 | CFRelease(newDict); |
131 | ||
dbf6a266 | 132 | #ifdef DEBUG |
9de8ab86 | 133 | SC_log(LOG_DEBUG, " _addWatcher: %@, %@", sessionNum, watchedKey); |
dbf6a266 | 134 | #endif /* DEBUG */ |
5958d7c0 A |
135 | |
136 | return; | |
137 | } | |
138 | ||
139 | ||
009ee3c6 | 140 | __private_extern__ |
5958d7c0 A |
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 | /* | |
0fae82ee | 155 | * Get the dictionary associated with this key out of the store |
5958d7c0 | 156 | */ |
0fae82ee | 157 | dict = CFDictionaryGetValue(storeData, watchedKey); |
942cecd7 | 158 | if ((dict == NULL) || !CFDictionaryContainsKey(dict, kSCDWatchers)) { |
5958d7c0 | 159 | /* key doesn't exist (isn't this really fatal?) */ |
dbf6a266 | 160 | #ifdef DEBUG |
9de8ab86 | 161 | SC_log(LOG_DEBUG, " _removeWatcher: %@, %@, key not watched", sessionNum, watchedKey); |
dbf6a266 | 162 | #endif /* DEBUG */ |
5958d7c0 A |
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); | |
dbf6a266 A |
181 | if (i == kCFNotFound) { |
182 | #ifdef DEBUG | |
9de8ab86 | 183 | SC_log(LOG_DEBUG, " _removeWatcher: %@, %@, session not watching", sessionNum, watchedKey); |
dbf6a266 | 184 | #endif /* DEBUG */ |
5958d7c0 A |
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 */ | |
0fae82ee | 218 | CFDictionarySetValue(storeData, watchedKey, newDict); |
5958d7c0 A |
219 | } else { |
220 | /* no information left, remove the empty dictionary */ | |
0fae82ee | 221 | CFDictionaryRemoveValue(storeData, watchedKey); |
5958d7c0 A |
222 | } |
223 | CFRelease(newDict); | |
224 | ||
dbf6a266 | 225 | #ifdef DEBUG |
9de8ab86 | 226 | SC_log(LOG_DEBUG, " _removeWatcher: %@, %@", sessionNum, watchedKey); |
dbf6a266 A |
227 | #endif /* DEBUG */ |
228 | ||
229 | return; | |
230 | } | |
231 | ||
232 | ||
5e9ce69e A |
233 | #define N_QUICK 64 |
234 | ||
235 | ||
dbf6a266 A |
236 | __private_extern__ |
237 | void | |
f715d946 | 238 | pushNotifications(void) |
dbf6a266 | 239 | { |
dbf6a266 A |
240 | CFIndex notifyCnt; |
241 | int server; | |
5e9ce69e A |
242 | const void * sessionsToNotify_q[N_QUICK]; |
243 | const void ** sessionsToNotify = sessionsToNotify_q; | |
dbf6a266 | 244 | SCDynamicStorePrivateRef storePrivate; |
5e9ce69e | 245 | serverSessionRef theSession; |
dbf6a266 A |
246 | |
247 | if (needsNotification == NULL) | |
248 | return; /* if no sessions need to be kicked */ | |
249 | ||
250 | notifyCnt = CFSetGetCount(needsNotification); | |
5e9ce69e A |
251 | if (notifyCnt > (CFIndex)(sizeof(sessionsToNotify_q) / sizeof(CFNumberRef))) |
252 | sessionsToNotify = CFAllocatorAllocate(NULL, notifyCnt * sizeof(CFNumberRef), 0); | |
dbf6a266 A |
253 | CFSetGetValues(needsNotification, sessionsToNotify); |
254 | while (--notifyCnt >= 0) { | |
255 | (void) CFNumberGetValue(sessionsToNotify[notifyCnt], | |
256 | kCFNumberIntType, | |
257 | &server); | |
258 | theSession = getSession(server); | |
942cecd7 A |
259 | assert(theSession != NULL); |
260 | ||
dbf6a266 A |
261 | storePrivate = (SCDynamicStorePrivateRef)theSession->store; |
262 | ||
263 | /* | |
1ef45fa4 | 264 | * deliver [CFRunLoop/dispatch] notifications to client sessions |
dbf6a266 A |
265 | */ |
266 | if ((storePrivate->notifyStatus == Using_NotifierInformViaMachPort) && | |
267 | (storePrivate->notifyPort != MACH_PORT_NULL)) { | |
dbf6a266 A |
268 | /* |
269 | * Post notification as mach message | |
270 | */ | |
942cecd7 | 271 | SC_trace("-->port : %5d : port = %d", |
9de8ab86 | 272 | storePrivate->server, |
77a550b6 A |
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 | } | |
a40a14f8 | 279 | |
edebe297 | 280 | _SC_sendMachMessage(storePrivate->notifyPort, storePrivate->notifyPortIdentifier); |
dbf6a266 A |
281 | } |
282 | ||
283 | if ((storePrivate->notifyStatus == Using_NotifierInformViaFD) && | |
284 | (storePrivate->notifyFile >= 0)) { | |
285 | ssize_t written; | |
286 | ||
942cecd7 | 287 | SC_trace("-->fd : %5d : fd = %d, msgid = %d", |
9de8ab86 A |
288 | storePrivate->server, |
289 | storePrivate->notifyFile, | |
290 | storePrivate->notifyFileIdentifier); | |
dbf6a266 A |
291 | |
292 | written = write(storePrivate->notifyFile, | |
293 | &storePrivate->notifyFileIdentifier, | |
294 | sizeof(storePrivate->notifyFileIdentifier)); | |
295 | if (written == -1) { | |
296 | if (errno == EWOULDBLOCK) { | |
297 | #ifdef DEBUG | |
9de8ab86 | 298 | SC_log(LOG_DEBUG, "sorry, only one outstanding notification per session"); |
dbf6a266 A |
299 | #endif /* DEBUG */ |
300 | } else { | |
301 | #ifdef DEBUG | |
9de8ab86 | 302 | SC_log(LOG_DEBUG, "could not send notification, write() failed: %s", |
dbf6a266 A |
303 | strerror(errno)); |
304 | #endif /* DEBUG */ | |
305 | storePrivate->notifyFile = -1; | |
306 | } | |
307 | } else if (written != sizeof(storePrivate->notifyFileIdentifier)) { | |
308 | #ifdef DEBUG | |
9de8ab86 | 309 | SC_log(LOG_DEBUG, "could not send notification, incomplete write()"); |
dbf6a266 A |
310 | #endif /* DEBUG */ |
311 | storePrivate->notifyFile = -1; | |
312 | } | |
313 | } | |
dbf6a266 | 314 | } |
5e9ce69e | 315 | if (sessionsToNotify != sessionsToNotify_q) CFAllocatorDeallocate(NULL, sessionsToNotify); |
dbf6a266 A |
316 | |
317 | /* | |
318 | * this list of notifications have been posted, wait for some more. | |
319 | */ | |
320 | CFRelease(needsNotification); | |
321 | needsNotification = NULL; | |
5958d7c0 A |
322 | |
323 | return; | |
324 | } |