2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
24 * Modification History
26 * June 1, 2001 Allan Nathanson <ajn@apple.com>
27 * - public API conversion
29 * March 24, 2000 Allan Nathanson <ajn@apple.com>
34 #include <mach/mach.h>
35 #include <mach/mach_error.h>
36 #include <servers/bootstrap.h>
38 #include <SystemConfiguration/SystemConfiguration.h>
39 #include <SystemConfiguration/SCPrivate.h>
40 #include "SCDynamicStoreInternal.h"
41 #include "config.h" /* MiG generated file */
44 __SCDynamicStoreCopyDescription(CFTypeRef cf
) {
45 CFAllocatorRef allocator
= CFGetAllocator(cf
);
46 CFMutableStringRef result
;
48 result
= CFStringCreateMutable(allocator
, 0);
49 CFStringAppendFormat(result
, NULL
, CFSTR("<SCDynamicStore %p [%p]> {\n"), cf
, allocator
);
50 CFStringAppendFormat(result
, NULL
, CFSTR("}"));
57 __SCDynamicStoreDeallocate(CFTypeRef cf
)
63 SCDynamicStoreRef store
= (SCDynamicStoreRef
)cf
;
64 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
66 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("__SCDynamicStoreDeallocate:"));
68 (void) pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED
, &oldThreadState
);
70 /* Remove notification keys */
71 keyCnt
= CFSetGetCount(storePrivate
->keys
);
73 const void **watchedKeys
;
74 CFArrayRef keysToRemove
;
77 watchedKeys
= CFAllocatorAllocate(NULL
, keyCnt
* sizeof(CFStringRef
), 0);
78 CFSetGetValues(storePrivate
->keys
, watchedKeys
);
79 keysToRemove
= CFArrayCreate(NULL
, watchedKeys
, keyCnt
, &kCFTypeArrayCallBacks
);
80 CFAllocatorDeallocate(NULL
, watchedKeys
);
81 for (i
=0; i
<keyCnt
; i
++) {
82 (void) SCDynamicStoreRemoveWatchedKey(store
,
83 CFArrayGetValueAtIndex(keysToRemove
, i
),
86 CFRelease(keysToRemove
);
89 /* Remove regex notification keys */
90 keyCnt
= CFSetGetCount(storePrivate
->reKeys
);
92 const void **watchedKeys
;
93 CFArrayRef keysToRemove
;
96 watchedKeys
= CFAllocatorAllocate(NULL
, keyCnt
* sizeof(CFStringRef
), 0);
97 CFSetGetValues(storePrivate
->reKeys
, watchedKeys
);
98 keysToRemove
= CFArrayCreate(NULL
, watchedKeys
, keyCnt
, &kCFTypeArrayCallBacks
);
99 CFAllocatorDeallocate(NULL
, watchedKeys
);
100 for (i
=0; i
<keyCnt
; i
++) {
101 (void) SCDynamicStoreRemoveWatchedKey(store
,
102 CFArrayGetValueAtIndex(keysToRemove
, i
),
105 CFRelease(keysToRemove
);
108 /* Remove/cancel any outstanding notification requests. */
109 (void) SCDynamicStoreNotifyCancel(store
);
111 if (storePrivate
->server
&& storePrivate
->locked
) {
112 (void) SCDynamicStoreUnlock(store
); /* release the lock */
115 if (storePrivate
->server
!= MACH_PORT_NULL
) {
116 status
= configclose(storePrivate
->server
, (int *)&sc_status
);
117 if (status
!= KERN_SUCCESS
) {
118 if (status
!= MACH_SEND_INVALID_DEST
)
119 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("configclose(): %s"), mach_error_string(status
));
122 (void) mach_port_destroy(mach_task_self(), storePrivate
->server
);
123 storePrivate
->server
= MACH_PORT_NULL
;
126 (void) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS
, &oldThreadState
);
127 pthread_testcancel();
129 /* release any callback context info */
130 if (storePrivate
->rlsContext
.release
) {
131 storePrivate
->rlsContext
.release(storePrivate
->rlsContext
.info
);
134 /* release any keys being watched */
135 CFRelease(storePrivate
->keys
);
136 CFRelease(storePrivate
->reKeys
);
142 static CFTypeID __kSCDynamicStoreTypeID
= _kCFRuntimeNotATypeID
;
145 static const CFRuntimeClass __SCDynamicStoreClass
= {
147 "SCDynamicStore", // className
150 __SCDynamicStoreDeallocate
, // dealloc
153 NULL
, // copyFormattingDesc
154 __SCDynamicStoreCopyDescription
// copyDebugDesc
158 static pthread_once_t initialized
= PTHREAD_ONCE_INIT
;
162 __SCDynamicStoreInitialize(void) {
163 __kSCDynamicStoreTypeID
= _CFRuntimeRegisterClass(&__SCDynamicStoreClass
);
169 __SCDynamicStoreCreatePrivate(CFAllocatorRef allocator
,
170 const CFStringRef name
,
171 SCDynamicStoreCallBack callout
,
172 SCDynamicStoreContext
*context
)
174 SCDynamicStorePrivateRef store
;
177 /* initialize runtime */
178 pthread_once(&initialized
, __SCDynamicStoreInitialize
);
180 /* allocate session */
181 size
= sizeof(SCDynamicStorePrivate
) - sizeof(CFRuntimeBase
);
182 store
= (SCDynamicStorePrivateRef
)_CFRuntimeCreateInstance(allocator
,
183 __kSCDynamicStoreTypeID
,
190 /* server side of the "configd" session */
191 store
->server
= MACH_PORT_NULL
;
194 store
->locked
= FALSE
;
196 /* SCDKeys being watched */
197 store
->keys
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
198 store
->reKeys
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
200 /* Notification status */
201 store
->notifyStatus
= NotifierNotRegistered
;
203 /* "client" information associated with SCDynamicStoreCreateRunLoopSource() */
206 store
->rlsFunction
= callout
;
207 store
->rlsContext
.info
= NULL
;
208 store
->rlsContext
.retain
= NULL
;
209 store
->rlsContext
.release
= NULL
;
210 store
->rlsContext
.copyDescription
= NULL
;
212 bcopy(context
, &store
->rlsContext
, sizeof(SCDynamicStoreContext
));
213 if (context
->retain
) {
214 store
->rlsContext
.info
= (void *)context
->retain(context
->info
);
218 /* "client" information associated with SCDynamicStoreNotifyCallback() */
219 store
->callbackFunction
= NULL
;
220 store
->callbackArgument
= NULL
;
221 store
->callbackPort
= NULL
;
222 store
->callbackRunLoop
= NULL
;
223 store
->callbackRunLoopSource
= NULL
;
225 /* "server" information associated with SCDynamicStoreNotifyMachPort(); */
226 store
->notifyPort
= MACH_PORT_NULL
;
227 store
->notifyPortIdentifier
= 0;
229 /* "server" information associated with SCDynamicStoreNotifyFileDescriptor(); */
230 store
->notifyFile
= -1;
231 store
->notifyFileIdentifier
= 0;
233 /* "server" information associated with SCDynamicStoreNotifySignal(); */
234 store
->notifySignal
= 0;
235 store
->notifySignalTask
= TASK_NULL
;
237 return (SCDynamicStoreRef
)store
;
242 SCDynamicStoreCreate(CFAllocatorRef allocator
,
244 SCDynamicStoreCallBack callout
,
245 SCDynamicStoreContext
*context
)
247 SCDynamicStoreRef store
;
248 SCDynamicStorePrivateRef storePrivate
;
249 kern_return_t status
;
250 mach_port_t bootstrap_port
;
253 CFDataRef xmlName
; /* serialized name */
258 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("SCDynamicStoreCreate:"));
259 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" name = %@"), name
);
262 * allocate and initialize a new session
264 store
= __SCDynamicStoreCreatePrivate(allocator
, name
, callout
, context
);
265 storePrivate
= (SCDynamicStorePrivateRef
)store
;
267 status
= task_get_bootstrap_port(mach_task_self(), &bootstrap_port
);
268 if (status
!= KERN_SUCCESS
) {
269 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("task_get_bootstrap_port(): %s"), mach_error_string(status
));
275 server_name
= getenv("SCD_SERVER");
277 server_name
= SCD_SERVER
;
280 status
= bootstrap_look_up(bootstrap_port
, server_name
, &server
);
282 case BOOTSTRAP_SUCCESS
:
283 /* service currently registered, "a good thing" (tm) */
285 case BOOTSTRAP_UNKNOWN_SERVICE
:
286 /* service not currently registered, try again later */
293 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("bootstrap_status: %s"), mach_error_string(status
));
300 /* serialize the name */
301 if (!_SCSerialize(name
, &xmlName
, (void **)&myNameRef
, &myNameLen
)) {
302 _SCErrorSet(kSCStatusFailed
);
306 /* open a new session with the server */
307 status
= configopen(server
, myNameRef
, myNameLen
, &storePrivate
->server
, (int *)&sc_status
);
312 if (status
!= KERN_SUCCESS
) {
313 if (status
!= MACH_SEND_INVALID_DEST
)
314 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("configopen(): %s"), mach_error_string(status
));
320 if (sc_status
!= kSCStatusOK
) {
322 _SCErrorSet(sc_status
);
326 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" server port = %d"), storePrivate
->server
);
332 SCDynamicStoreGetTypeID(void) {
333 return __kSCDynamicStoreTypeID
;