]> git.saurik.com Git - apple/configd.git/blame - configd.tproj/_SCD.c
configd-888.51.2.tar.gz
[apple/configd.git] / configd.tproj / _SCD.c
CommitLineData
5958d7c0 1/*
942cecd7 2 * Copyright (c) 2000, 2001, 2003-2005, 2009, 2011, 2012, 2015, 2016 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 sessionData = NULL;
0fae82ee 43
009ee3c6 44__private_extern__ CFMutableDictionaryRef storeData = NULL;
5958d7c0 45
009ee3c6 46__private_extern__ CFMutableDictionaryRef patternData = NULL;
5958d7c0 47
009ee3c6 48__private_extern__ CFMutableSetRef changedKeys = NULL;
5958d7c0 49
009ee3c6 50__private_extern__ CFMutableSetRef deferredRemovals = NULL;
5958d7c0 51
009ee3c6 52__private_extern__ CFMutableSetRef removedSessionKeys = NULL;
5958d7c0 53
009ee3c6 54__private_extern__ CFMutableSetRef needsNotification = NULL;
5958d7c0 55
5958d7c0 56
009ee3c6 57__private_extern__
5958d7c0
A
58void
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 /*
0fae82ee 72 * Get the dictionary associated with this key out of the store
5958d7c0 73 */
0fae82ee 74 dict = CFDictionaryGetValue(storeData, watchedKey);
942cecd7 75 if (dict != NULL) {
5958d7c0
A
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);
dbf6a266 103 if (i == kCFNotFound) {
5958d7c0
A
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 /*
0fae82ee 129 * Update the store for this key
5958d7c0 130 */
0fae82ee 131 CFDictionarySetValue(storeData, watchedKey, newDict);
5958d7c0
A
132 CFRelease(newDict);
133
dbf6a266 134#ifdef DEBUG
9de8ab86 135 SC_log(LOG_DEBUG, " _addWatcher: %@, %@", sessionNum, watchedKey);
dbf6a266 136#endif /* DEBUG */
5958d7c0
A
137
138 return;
139}
140
141
009ee3c6 142__private_extern__
5958d7c0
A
143void
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 /*
0fae82ee 157 * Get the dictionary associated with this key out of the store
5958d7c0 158 */
0fae82ee 159 dict = CFDictionaryGetValue(storeData, watchedKey);
942cecd7 160 if ((dict == NULL) || !CFDictionaryContainsKey(dict, kSCDWatchers)) {
5958d7c0 161 /* key doesn't exist (isn't this really fatal?) */
dbf6a266 162#ifdef DEBUG
9de8ab86 163 SC_log(LOG_DEBUG, " _removeWatcher: %@, %@, key not watched", sessionNum, watchedKey);
dbf6a266 164#endif /* DEBUG */
5958d7c0
A
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);
dbf6a266
A
183 if (i == kCFNotFound) {
184#ifdef DEBUG
9de8ab86 185 SC_log(LOG_DEBUG, " _removeWatcher: %@, %@, session not watching", sessionNum, watchedKey);
dbf6a266 186#endif /* DEBUG */
5958d7c0
A
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 */
0fae82ee 220 CFDictionarySetValue(storeData, watchedKey, newDict);
5958d7c0
A
221 } else {
222 /* no information left, remove the empty dictionary */
0fae82ee 223 CFDictionaryRemoveValue(storeData, watchedKey);
5958d7c0
A
224 }
225 CFRelease(newDict);
226
dbf6a266 227#ifdef DEBUG
9de8ab86 228 SC_log(LOG_DEBUG, " _removeWatcher: %@, %@", sessionNum, watchedKey);
dbf6a266
A
229#endif /* DEBUG */
230
231 return;
232}
233
234
5e9ce69e
A
235#define N_QUICK 64
236
237
dbf6a266
A
238__private_extern__
239void
942cecd7 240pushNotifications()
dbf6a266 241{
dbf6a266
A
242 CFIndex notifyCnt;
243 int server;
5e9ce69e
A
244 const void * sessionsToNotify_q[N_QUICK];
245 const void ** sessionsToNotify = sessionsToNotify_q;
dbf6a266 246 SCDynamicStorePrivateRef storePrivate;
5e9ce69e 247 serverSessionRef theSession;
dbf6a266
A
248
249 if (needsNotification == NULL)
250 return; /* if no sessions need to be kicked */
251
252 notifyCnt = CFSetGetCount(needsNotification);
5e9ce69e
A
253 if (notifyCnt > (CFIndex)(sizeof(sessionsToNotify_q) / sizeof(CFNumberRef)))
254 sessionsToNotify = CFAllocatorAllocate(NULL, notifyCnt * sizeof(CFNumberRef), 0);
dbf6a266
A
255 CFSetGetValues(needsNotification, sessionsToNotify);
256 while (--notifyCnt >= 0) {
257 (void) CFNumberGetValue(sessionsToNotify[notifyCnt],
258 kCFNumberIntType,
259 &server);
260 theSession = getSession(server);
942cecd7
A
261 assert(theSession != NULL);
262
dbf6a266
A
263 storePrivate = (SCDynamicStorePrivateRef)theSession->store;
264
265 /*
266 * deliver notifications to client sessions
267 */
268 if ((storePrivate->notifyStatus == Using_NotifierInformViaMachPort) &&
269 (storePrivate->notifyPort != MACH_PORT_NULL)) {
942cecd7
A
270 /*
271 * Associate notification activity with the client
272 */
273 os_activity_scope(theSession->activity);
274
dbf6a266
A
275 /*
276 * Post notification as mach message
277 */
942cecd7 278 SC_trace("-->port : %5d : port = %d",
9de8ab86 279 storePrivate->server,
77a550b6
A
280 storePrivate->notifyPort);
281
282 /* use a random (and non-zero) identifier */
283 while (storePrivate->notifyPortIdentifier == 0) {
284 storePrivate->notifyPortIdentifier = (mach_msg_id_t)random();
285 }
a40a14f8 286
edebe297 287 _SC_sendMachMessage(storePrivate->notifyPort, storePrivate->notifyPortIdentifier);
dbf6a266
A
288 }
289
290 if ((storePrivate->notifyStatus == Using_NotifierInformViaFD) &&
291 (storePrivate->notifyFile >= 0)) {
292 ssize_t written;
293
942cecd7
A
294 /*
295 * Associate notification activity with the client
296 */
297 os_activity_scope(theSession->activity);
298
299 SC_trace("-->fd : %5d : fd = %d, msgid = %d",
9de8ab86
A
300 storePrivate->server,
301 storePrivate->notifyFile,
302 storePrivate->notifyFileIdentifier);
dbf6a266
A
303
304 written = write(storePrivate->notifyFile,
305 &storePrivate->notifyFileIdentifier,
306 sizeof(storePrivate->notifyFileIdentifier));
307 if (written == -1) {
308 if (errno == EWOULDBLOCK) {
309#ifdef DEBUG
9de8ab86 310 SC_log(LOG_DEBUG, "sorry, only one outstanding notification per session");
dbf6a266
A
311#endif /* DEBUG */
312 } else {
313#ifdef DEBUG
9de8ab86 314 SC_log(LOG_DEBUG, "could not send notification, write() failed: %s",
dbf6a266
A
315 strerror(errno));
316#endif /* DEBUG */
317 storePrivate->notifyFile = -1;
318 }
319 } else if (written != sizeof(storePrivate->notifyFileIdentifier)) {
320#ifdef DEBUG
9de8ab86 321 SC_log(LOG_DEBUG, "could not send notification, incomplete write()");
dbf6a266
A
322#endif /* DEBUG */
323 storePrivate->notifyFile = -1;
324 }
325 }
326
327 if ((storePrivate->notifyStatus == Using_NotifierInformViaSignal) &&
328 (storePrivate->notifySignal > 0)) {
329 kern_return_t status;
330 pid_t pid;
942cecd7
A
331
332 /*
333 * Associate notification activity with the client
334 */
335 os_activity_scope(theSession->activity);
336
dbf6a266
A
337 /*
338 * Post notification as signal
339 */
340 status = pid_for_task(storePrivate->notifySignalTask, &pid);
341 if (status == KERN_SUCCESS) {
942cecd7 342 SC_trace("-->sig : %5d : pid = %d, signal = sig%s (%d)",
9de8ab86
A
343 storePrivate->server,
344 pid,
345 sys_signame[storePrivate->notifySignal],
346 storePrivate->notifySignal);
a40a14f8 347
dbf6a266 348 if (kill(pid, storePrivate->notifySignal) != 0) {
a40a14f8 349 if (errno != ESRCH) {
9de8ab86
A
350 SC_log(LOG_NOTICE, "could not send sig%s to PID %d: %s",
351 sys_signame[storePrivate->notifySignal],
352 pid,
353 strerror(errno));
a40a14f8 354 }
dbf6a266
A
355 }
356 } else {
357 mach_port_type_t pt;
358
a40a14f8
A
359 __MACH_PORT_DEBUG(TRUE, "*** pushNotifications pid_for_task failed: releasing task", storePrivate->notifySignalTask);
360 if (mach_port_type(mach_task_self(), storePrivate->notifySignalTask, &pt) == KERN_SUCCESS) {
361 if ((pt & MACH_PORT_TYPE_DEAD_NAME) != 0) {
9de8ab86 362 SC_log(LOG_NOTICE, "pid_for_task() failed: %s", mach_error_string(status));
a40a14f8 363 }
dbf6a266 364 } else {
9de8ab86 365 SC_log(LOG_NOTICE, "mach_port_type() failed: %s", mach_error_string(status));
dbf6a266 366 }
dbf6a266 367
dbf6a266 368 /* don't bother with any more attempts */
a40a14f8 369 (void) mach_port_deallocate(mach_task_self(), storePrivate->notifySignalTask);
dbf6a266
A
370 storePrivate->notifySignal = 0;
371 storePrivate->notifySignalTask = TASK_NULL;
372 }
373 }
374 }
5e9ce69e 375 if (sessionsToNotify != sessionsToNotify_q) CFAllocatorDeallocate(NULL, sessionsToNotify);
dbf6a266
A
376
377 /*
378 * this list of notifications have been posted, wait for some more.
379 */
380 CFRelease(needsNotification);
381 needsNotification = NULL;
5958d7c0
A
382
383 return;
384}