2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * May 13, 2004 Allan Nathanson <ajn@apple.com>
32 #include <CoreFoundation/CoreFoundation.h>
33 #include <CoreFoundation/CFRuntime.h>
34 #include <SystemConfiguration/SystemConfiguration.h>
35 #include <SystemConfiguration/SCNetworkConfigurationInternal.h>
36 #include <SystemConfiguration/SCValidation.h>
37 #include <SystemConfiguration/SCPrivate.h>
39 #include "SCNetworkConfiguration.h"
40 #include "SCNetworkConfigurationInternal.h"
45 static CFStringRef
__SCNetworkSetCopyDescription (CFTypeRef cf
);
46 static void __SCNetworkSetDeallocate (CFTypeRef cf
);
47 static Boolean
__SCNetworkSetEqual (CFTypeRef cf1
, CFTypeRef cf2
);
50 static CFTypeID __kSCNetworkSetTypeID
= _kCFRuntimeNotATypeID
;
53 static const CFRuntimeClass __SCNetworkSetClass
= {
55 "SCNetworkSet", // className
58 __SCNetworkSetDeallocate
, // dealloc
59 __SCNetworkSetEqual
, // equal
61 NULL
, // copyFormattingDesc
62 __SCNetworkSetCopyDescription
// copyDebugDesc
66 static pthread_once_t initialized
= PTHREAD_ONCE_INIT
;
69 static __inline__ CFTypeRef
70 isA_SCNetworkSet(CFTypeRef obj
)
72 return (isA_CFType(obj
, SCNetworkSetGetTypeID()));
77 __SCNetworkSetCopyDescription(CFTypeRef cf
)
79 CFAllocatorRef allocator
= CFGetAllocator(cf
);
80 CFMutableStringRef result
;
81 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)cf
;
83 result
= CFStringCreateMutable(allocator
, 0);
84 CFStringAppendFormat(result
, NULL
, CFSTR("<SCNetworkSet %p [%p]> { "), cf
, allocator
);
85 CFStringAppendFormat(result
, NULL
, CFSTR("id=%@"), setPrivate
->setID
);
86 // CFStringAppendFormat(result, NULL, CFSTR(", prefs=%@"), setPrivate->prefs);
87 CFStringAppendFormat(result
, NULL
, CFSTR(" }"));
94 __SCNetworkSetDeallocate(CFTypeRef cf
)
96 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)cf
;
98 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("__SCNetworkSetDeallocate:"));
100 /* release resources */
102 CFRelease(setPrivate
->setID
);
103 CFRelease(setPrivate
->prefs
);
110 __SCNetworkSetEqual(CFTypeRef cf1
, CFTypeRef cf2
)
112 SCNetworkSetPrivateRef s1
= (SCNetworkSetPrivateRef
)cf1
;
113 SCNetworkSetPrivateRef s2
= (SCNetworkSetPrivateRef
)cf2
;
118 if (s1
->prefs
!= s2
->prefs
)
119 return FALSE
; // if not the same prefs
121 if (!CFEqual(s1
->setID
, s2
->setID
))
122 return FALSE
; // if not the same set identifier
129 __SCNetworkSetInitialize(void)
131 __kSCNetworkSetTypeID
= _CFRuntimeRegisterClass(&__SCNetworkSetClass
);
136 static SCNetworkSetPrivateRef
137 __SCNetworkSetCreatePrivate(CFAllocatorRef allocator
,
138 SCPreferencesRef prefs
,
141 SCNetworkSetPrivateRef setPrivate
;
144 /* initialize runtime */
145 pthread_once(&initialized
, __SCNetworkSetInitialize
);
147 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("__SCNetworkSetCreatePrivate:"));
149 /* allocate target */
150 size
= sizeof(SCNetworkSetPrivate
) - sizeof(CFRuntimeBase
);
151 setPrivate
= (SCNetworkSetPrivateRef
)_CFRuntimeCreateInstance(allocator
,
152 __kSCNetworkSetTypeID
,
155 if (setPrivate
== NULL
) {
159 setPrivate
->setID
= CFStringCreateCopy(NULL
, setID
);
160 setPrivate
->prefs
= CFRetain(prefs
);
170 SCNetworkSetAddService(SCNetworkSetRef set
, SCNetworkServiceRef service
)
172 SCNetworkInterfaceRef interface
;
173 CFArrayRef interface_config
= NULL
;
177 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
178 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
180 #define PREVENT_DUPLICATE_SETS
181 #ifdef PREVENT_DUPLICATE_SETS
184 // ensure that each service is only a member of ONE set
186 sets
= SCNetworkSetCopyAll(setPrivate
->prefs
);
191 n
= CFArrayGetCount(sets
);
192 for (i
= 0; i
< n
; i
++) {
197 set
= CFArrayGetValueAtIndex(sets
, i
);
198 services
= SCNetworkSetCopyServices(set
);
199 found
= CFArrayContainsValue(services
,
200 CFRangeMake(0, CFArrayGetCount(services
)),
206 _SCErrorSet(kSCStatusKeyExists
);
212 #endif /* PREVENT_DUPLICATE_SETS */
214 // get the [deep] interface configuration settings
215 interface
= SCNetworkServiceGetInterface(service
);
216 if (interface
!= NULL
) {
217 interface_config
= __SCNetworkInterfaceCopyDeepConfiguration(interface
);
220 // create the link between "set" and the "service"
221 path
= SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL
, // allocator
222 setPrivate
->setID
, // set
223 servicePrivate
->serviceID
, // service
225 link
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
, // allocator
226 servicePrivate
->serviceID
, // service
228 ok
= SCPreferencesPathSetLink(setPrivate
->prefs
, path
, link
);
235 // push the [deep] interface configuration into all sets which contain this service.
236 if (interface
!= NULL
) {
237 __SCNetworkInterfaceSetDeepConfiguration(interface
, interface_config
);
245 SCNetworkSetCopy(SCPreferencesRef prefs
, CFStringRef setID
)
247 CFDictionaryRef entity
;
249 SCNetworkSetPrivateRef setPrivate
;
251 path
= SCPreferencesPathKeyCreateSet(NULL
, setID
);
252 entity
= SCPreferencesPathGetValue(prefs
, path
);
255 if (!isA_CFDictionary(entity
)) {
256 _SCErrorSet(kSCStatusNoKey
);
260 setPrivate
= __SCNetworkSetCreatePrivate(NULL
, prefs
, setID
);
261 return (SCNetworkSetRef
)setPrivate
;
265 CFArrayRef
/* of SCNetworkServiceRef's */
266 SCNetworkSetCopyAll(SCPreferencesRef prefs
)
268 CFMutableArrayRef array
;
271 CFDictionaryRef sets
;
273 path
= SCPreferencesPathKeyCreateSets(NULL
);
274 sets
= SCPreferencesPathGetValue(prefs
, path
);
277 if ((sets
!= NULL
) && !isA_CFDictionary(sets
)) {
281 array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
283 n
= (sets
!= NULL
) ? CFDictionaryGetCount(sets
) : 0;
286 const void * keys_q
[N_QUICK
];
287 const void ** keys
= keys_q
;
288 const void * vals_q
[N_QUICK
];
289 const void ** vals
= vals_q
;
291 if (n
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
292 keys
= CFAllocatorAllocate(NULL
, n
* sizeof(CFTypeRef
), 0);
293 vals
= CFAllocatorAllocate(NULL
, n
* sizeof(CFPropertyListRef
), 0);
295 CFDictionaryGetKeysAndValues(sets
, keys
, vals
);
296 for (i
= 0; i
< n
; i
++) {
297 SCNetworkSetPrivateRef setPrivate
;
299 if (!isA_CFDictionary(vals
[i
])) {
302 CFSTR("SCNetworkSetCopyAll(): error w/set \"%@\"\n"),
307 setPrivate
= __SCNetworkSetCreatePrivate(NULL
, prefs
, keys
[i
]);
308 CFArrayAppendValue(array
, (SCNetworkSetRef
)setPrivate
);
309 CFRelease(setPrivate
);
311 if (keys
!= keys_q
) {
312 CFAllocatorDeallocate(NULL
, keys
);
313 CFAllocatorDeallocate(NULL
, vals
);
322 SCNetworkSetCopyCurrent(SCPreferencesRef prefs
)
324 CFArrayRef components
;
325 CFStringRef currentID
;
326 SCNetworkSetPrivateRef setPrivate
= NULL
;
328 currentID
= SCPreferencesGetValue(prefs
, kSCPrefCurrentSet
);
329 if (!isA_CFString(currentID
)) {
333 components
= CFStringCreateArrayBySeparatingStrings(NULL
, currentID
, CFSTR("/"));
334 if (CFArrayGetCount(components
) == 3) {
338 setID
= CFArrayGetValueAtIndex(components
, 2);
339 path
= SCPreferencesPathKeyCreateSet(NULL
, setID
);
340 if (CFEqual(path
, currentID
)) {
341 setPrivate
= __SCNetworkSetCreatePrivate(NULL
, prefs
, setID
);
343 SCLog(TRUE
, LOG_ERR
, CFSTR("SCNetworkSetCopyCurrent(): preferences are non-conformant"));
347 CFRelease(components
);
349 return (SCNetworkSetRef
)setPrivate
;
353 CFArrayRef
/* of SCNetworkServiceRef's */
354 SCNetworkSetCopyServices(SCNetworkSetRef set
)
356 CFMutableArrayRef array
;
357 CFDictionaryRef dict
;
360 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
362 path
= SCPreferencesPathKeyCreateSetNetworkService(NULL
, setPrivate
->setID
, NULL
);
363 dict
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
365 if ((dict
!= NULL
) && !isA_CFDictionary(dict
)) {
369 array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
371 n
= (dict
!= NULL
) ? CFDictionaryGetCount(dict
) : 0;
374 const void * keys_q
[N_QUICK
];
375 const void ** keys
= keys_q
;
377 if (n
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
378 keys
= CFAllocatorAllocate(NULL
, n
* sizeof(CFTypeRef
), 0);
380 CFDictionaryGetKeysAndValues(dict
, keys
, NULL
);
381 for (i
= 0; i
< n
; i
++) {
382 CFArrayRef components
;
385 path
= SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL
,
387 (CFStringRef
)keys
[i
],
389 link
= SCPreferencesPathGetLink(setPrivate
->prefs
, path
);
394 CFSTR("SCNetworkSetCopyServices(): service \"%@\" for set \"%@\" is not a link\n"),
397 continue; // if the service is not a link
400 components
= CFStringCreateArrayBySeparatingStrings(NULL
, link
, CFSTR("/"));
401 if (CFArrayGetCount(components
) == 3) {
402 CFStringRef serviceID
;
404 serviceID
= CFArrayGetValueAtIndex(components
, 2);
405 path
= SCPreferencesPathKeyCreateNetworkServiceEntity(NULL
, // allocator
406 serviceID
, // service
408 if (CFEqual(path
, link
)) {
409 SCNetworkServicePrivateRef servicePrivate
;
411 servicePrivate
= __SCNetworkServiceCreatePrivate(NULL
,
415 CFArrayAppendValue(array
, (SCNetworkServiceRef
)servicePrivate
);
416 CFRelease(servicePrivate
);
420 CFRelease(components
);
422 if (keys
!= keys_q
) {
423 CFAllocatorDeallocate(NULL
, keys
);
432 SCNetworkSetCreate(SCPreferencesRef prefs
)
434 CFArrayRef components
;
438 SCNetworkSetPrivateRef setPrivate
;
440 prefix
= SCPreferencesPathKeyCreateSets(NULL
);
441 path
= SCPreferencesPathCreateUniqueChild(prefs
, prefix
);
447 components
= CFStringCreateArrayBySeparatingStrings(NULL
, path
, CFSTR("/"));
450 setID
= CFArrayGetValueAtIndex(components
, 2);
451 setPrivate
= __SCNetworkSetCreatePrivate(NULL
, prefs
, setID
);
452 CFRelease(components
);
454 return (SCNetworkSetRef
)setPrivate
;
459 SCNetworkSetGetSetID(SCNetworkSetRef set
)
461 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
463 return setPrivate
->setID
;
468 SCNetworkSetGetName(SCNetworkSetRef set
)
470 CFDictionaryRef entity
;
471 CFStringRef name
= NULL
;
473 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
475 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
476 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
479 if (isA_CFDictionary(entity
)) {
480 name
= CFDictionaryGetValue(entity
, kSCPropUserDefinedName
);
483 return isA_CFString(name
) ? name
: NULL
;
487 CFArrayRef
/* of serviceID CFStringRef's */
488 SCNetworkSetGetServiceOrder(SCNetworkSetRef set
)
490 CFDictionaryRef dict
;
492 CFArrayRef serviceOrder
;
493 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
495 path
= SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL
, setPrivate
->setID
, kSCEntNetIPv4
);
500 dict
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
502 if (!isA_CFDictionary(dict
)) {
506 serviceOrder
= CFDictionaryGetValue(dict
, kSCPropNetServiceOrder
);
507 serviceOrder
= isA_CFArray(serviceOrder
);
514 SCNetworkSetGetTypeID(void)
516 pthread_once(&initialized
, __SCNetworkSetInitialize
); /* initialize runtime */
517 return __kSCNetworkSetTypeID
;
522 SCNetworkSetRemove(SCNetworkSetRef set
)
524 CFStringRef currentPath
;
527 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
529 currentPath
= SCPreferencesGetValue(setPrivate
->prefs
, kSCPrefCurrentSet
);
530 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
531 if (!isA_CFString(currentPath
) || !CFEqual(currentPath
, path
)) {
532 ok
= SCPreferencesPathRemoveValue(setPrivate
->prefs
, path
);
541 SCNetworkSetRemoveService(SCNetworkSetRef set
, SCNetworkServiceRef service
)
543 SCNetworkInterfaceRef interface
;
544 CFArrayRef interface_config
= NULL
;
547 SCNetworkServicePrivateRef servicePrivate
= (SCNetworkServicePrivateRef
)service
;
548 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
550 // get the [deep] interface configuration settings
551 interface
= SCNetworkServiceGetInterface(service
);
552 if (interface
!= NULL
) {
553 interface_config
= __SCNetworkInterfaceCopyDeepConfiguration(interface
);
554 if (interface_config
!= NULL
) {
555 // remove the interface configuration from all sets which contain this service.
556 __SCNetworkInterfaceSetDeepConfiguration(interface
, NULL
);
560 // remove the link between "set" and the "service"
561 path
= SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL
,
563 servicePrivate
->serviceID
,
565 ok
= SCPreferencesPathRemoveValue(setPrivate
->prefs
, path
);
571 // push the [deep] interface configuration [back] into all sets which contain the service.
572 if (interface_config
!= NULL
) {
573 __SCNetworkInterfaceSetDeepConfiguration(interface
, interface_config
);
578 if (interface_config
!= NULL
) CFRelease(interface_config
);
584 SCNetworkSetSetCurrent(SCNetworkSetRef set
)
588 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
590 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
591 ok
= SCPreferencesSetValue(setPrivate
->prefs
, kSCPrefCurrentSet
, path
);
598 SCNetworkSetSetName(SCNetworkSetRef set
, CFStringRef name
)
600 CFDictionaryRef entity
;
603 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
605 #define PREVENT_DUPLICATE_SET_NAMES
606 #ifdef PREVENT_DUPLICATE_SET_NAMES
607 if (isA_CFString(name
)) {
610 // ensure that each set is uniquely named
612 sets
= SCNetworkSetCopyAll(setPrivate
->prefs
);
617 n
= CFArrayGetCount(sets
);
618 for (i
= 0; i
< n
; i
++) {
620 CFStringRef otherName
;
621 SCNetworkSetRef set
= CFArrayGetValueAtIndex(sets
, i
);
623 otherID
= SCNetworkSetGetSetID(set
);
624 if (CFEqual(setPrivate
->setID
, otherID
)) {
625 continue; // skip current set
628 otherName
= SCNetworkSetGetName(set
);
629 if ((otherName
!= NULL
) && CFEqual(name
, otherName
)) {
630 // if "name" not unique
632 _SCErrorSet(kSCStatusKeyExists
);
639 #endif /* PREVENT_DUPLICATE_SET_NAMES */
643 path
= SCPreferencesPathKeyCreateSet(NULL
, setPrivate
->setID
);
644 entity
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
645 if ((entity
== NULL
) && (name
!= NULL
)) {
646 entity
= CFDictionaryCreate(NULL
,
650 &kCFTypeDictionaryKeyCallBacks
,
651 &kCFTypeDictionaryValueCallBacks
);
653 if (isA_CFDictionary(entity
)) {
654 CFMutableDictionaryRef newEntity
;
656 newEntity
= CFDictionaryCreateMutableCopy(NULL
, 0, entity
);
657 if (isA_CFString(name
)) {
658 CFDictionarySetValue(newEntity
, kSCPropUserDefinedName
, name
);
660 CFDictionaryRemoveValue(newEntity
, kSCPropUserDefinedName
);
662 ok
= SCPreferencesPathSetValue(setPrivate
->prefs
, path
, newEntity
);
663 CFRelease(newEntity
);
672 SCNetworkSetSetServiceOrder(SCNetworkSetRef set
, CFArrayRef newOrder
)
674 CFDictionaryRef dict
;
675 CFMutableDictionaryRef newDict
;
678 SCNetworkSetPrivateRef setPrivate
= (SCNetworkSetPrivateRef
)set
;
680 path
= SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL
, setPrivate
->setID
, kSCEntNetIPv4
);
685 dict
= SCPreferencesPathGetValue(setPrivate
->prefs
, path
);
687 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
689 newDict
= CFDictionaryCreateMutable(NULL
,
691 &kCFTypeDictionaryKeyCallBacks
,
692 &kCFTypeDictionaryValueCallBacks
);
695 CFDictionarySetValue(newDict
, kSCPropNetServiceOrder
, newOrder
);
696 ok
= SCPreferencesPathSetValue(setPrivate
->prefs
, path
, newDict
);