1/*
2 * Copyright (c) 2000, 2001, 2003, 2004, 2006-2012 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 * March 24, 2000		Allan Nathanson <ajn@apple.com>
31 * - initial revision
32 */
33
34#include <unistd.h>
35
36#include "configd.h"
37#include "session.h"
38
39static Boolean
40isMySessionKey(CFStringRef sessionKey, CFStringRef key)
41{
42	CFDictionaryRef	dict;
43	CFStringRef	storeSessionKey;
44
45	dict = CFDictionaryGetValue(storeData, key);
46	if (!dict) {
47		/* if key no longer exists */
48		return FALSE;
49	}
50
51	storeSessionKey = CFDictionaryGetValue(dict, kSCDSession);
52	if (!storeSessionKey) {
53		/* if this is not a session key */
54		return FALSE;
55	}
56
57	if (!CFEqual(sessionKey, storeSessionKey)) {
58		/* if this is not "my" session key */
59		return FALSE;
60	}
61
62	return TRUE;
63}
64
65
66static void
67removeAllKeys(SCDynamicStoreRef store, Boolean isRegex)
68{
69	SCDynamicStorePrivateRef	storePrivate	= (SCDynamicStorePrivateRef)store;
70	CFArrayRef			keys;
71	CFIndex				n;
72
73	keys = isRegex ? storePrivate->patterns : storePrivate->keys;
74	n = (keys != NULL) ? CFArrayGetCount(keys) : 0;
75	if (n > 0) {
76		CFIndex		i;
77		CFArrayRef	keysToRemove;
78
79		keysToRemove = CFArrayCreateCopy(NULL, keys);
80		for (i = 0; i < n; i++) {
81			(void) __SCDynamicStoreRemoveWatchedKey(store,
82								CFArrayGetValueAtIndex(keysToRemove, i),
83								isRegex,
84								TRUE);
85		}
86		CFRelease(keysToRemove);
87	}
88
89	return;
90}
91
92
93__private_extern__
94int
95__SCDynamicStoreClose(SCDynamicStoreRef *store)
96{
97	CFDictionaryRef			dict;
98	CFArrayRef			keys;
99	CFIndex				keyCnt;
100	serverSessionRef		mySession;
101	CFStringRef			sessionKey;
102	SCDynamicStorePrivateRef	storePrivate = (SCDynamicStorePrivateRef)*store;
103
104	if (_configd_trace) {
105		SCTrace(TRUE, _configd_trace,
106			CFSTR("close   : %5d\n"),
107			storePrivate->server);
108	}
109
110	/* Remove all notification keys and patterns */
111	removeAllKeys(*store, FALSE);	// keys
112	removeAllKeys(*store, TRUE);	// patterns
113
114	/* Remove/cancel any outstanding notification requests. */
115	__MACH_PORT_DEBUG(storePrivate->notifyPort != MACH_PORT_NULL, "*** __SCDynamicStoreClose", storePrivate->notifyPort);
116	(void) __SCDynamicStoreNotifyCancel(*store);
117
118	/* Remove any session keys */
119	sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), storePrivate->server);
120	dict = CFDictionaryGetValue(sessionData, sessionKey);
121	keys = CFDictionaryGetValue(dict, kSCDSessionKeys);
122	if (keys && ((keyCnt = CFArrayGetCount(keys)) > 0)) {
123		CFIndex	i;
124		Boolean	push	= FALSE;
125
126		/* remove session keys */
127		for (i = 0; i < keyCnt; i++) {
128			if (isMySessionKey(sessionKey, CFArrayGetValueAtIndex(keys, i))) {
129				(void) __SCDynamicStoreRemoveValue(*store, CFArrayGetValueAtIndex(keys, i), TRUE);
130				push = TRUE;
131			}
132		}
133
134		if (push) {
135			/* push changes */
136			(void) __SCDynamicStorePush();
137		}
138	}
139	CFRelease(sessionKey);
140
141	/*
142	 * invalidate and release our run loop source on the server
143	 * port (for this client).  Then, release the port.
144	 */
145	mySession = getSession(storePrivate->server);
146	if (mySession->serverRunLoopSource) {
147		CFRunLoopSourceInvalidate(mySession->serverRunLoopSource);
148		CFRelease(mySession->serverRunLoopSource);
149		mySession->serverRunLoopSource = NULL;
150	}
151	if (mySession->serverPort != NULL) {
152		CFMachPortInvalidate(mySession->serverPort);
153		CFRelease(mySession->serverPort);
154		mySession->serverPort = NULL;
155	}
156
157	storePrivate->server = MACH_PORT_NULL;
158	CFRelease(*store);
159	*store = NULL;
160
161	return kSCStatusOK;
162}
163