2 * Copyright (c) 2000-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 * June 1, 2001 Allan Nathanson <ajn@apple.com>
28 * - public API conversion
30 * November 9, 2000 Allan Nathanson <ajn@apple.com>
34 #include <SystemConfiguration/SystemConfiguration.h>
35 #include <SystemConfiguration/SCValidation.h>
36 #include <SystemConfiguration/SCPrivate.h>
38 #include <sys/types.h>
39 #include <sys/socket.h>
41 #include <net/if_dl.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
45 #include <mach/mach.h>
46 #include <mach/notify.h>
47 #include <mach/mach_error.h>
54 _SC_cfstring_to_cstring(CFStringRef cfstr
, char *buf
, int bufLen
, CFStringEncoding encoding
)
57 CFIndex len
= CFStringGetLength(cfstr
);
59 /* how much buffer space will we really need? */
60 (void)CFStringGetBytes(cfstr
,
70 /* check the size of the provided buffer */
71 if (bufLen
< (len
+ 1)) {
72 return NULL
; /* if too small */
75 /* allocate a buffer */
77 buf
= CFAllocatorAllocate(NULL
, bufLen
, 0);
83 (void)CFStringGetBytes(cfstr
,
98 _SC_sockaddr_to_string(const struct sockaddr
*address
, char *buf
, size_t bufLen
)
101 switch (address
->sa_family
) {
103 (void)inet_ntop(((struct sockaddr_in
*)address
)->sin_family
,
104 &((struct sockaddr_in
*)address
)->sin_addr
,
109 (void)inet_ntop(((struct sockaddr_in6
*)address
)->sin6_family
,
110 &((struct sockaddr_in6
*)address
)->sin6_addr
,
113 if (((struct sockaddr_in6
*)address
)->sin6_scope_id
!= 0) {
117 if ((n
+IF_NAMESIZE
+1) <= (int)bufLen
) {
119 if_indextoname(((struct sockaddr_in6
*)address
)->sin6_scope_id
, &buf
[n
]);
125 if (((struct sockaddr_dl
*)address
)->sdl_len
< bufLen
) {
126 bufLen
= ((struct sockaddr_dl
*)address
)->sdl_len
;
131 bcopy(((struct sockaddr_dl
*)address
)->sdl_data
, buf
, bufLen
);
134 snprintf(buf
, bufLen
, "unexpected address family %d", address
->sa_family
);
143 _SCSerialize(CFPropertyListRef obj
, CFDataRef
*xml
, void **dataRef
, CFIndex
*dataLen
)
146 CFWriteStreamRef stream
;
148 if (!xml
&& !(dataRef
&& dataLen
)) {
149 /* if not keeping track of allocated space */
153 stream
= CFWriteStreamCreateWithAllocatedBuffers(NULL
, NULL
);
154 CFWriteStreamOpen(stream
);
155 CFPropertyListWriteToStream(obj
, stream
, kCFPropertyListBinaryFormat_v1_0
, NULL
);
156 CFWriteStreamClose(stream
);
157 myXml
= CFWriteStreamCopyProperty(stream
, kCFStreamPropertyDataWritten
);
160 SCLog(TRUE
, LOG_ERR
, CFSTR("_SCSerialize() failed"));
161 if (xml
) *xml
= NULL
;
162 if (dataRef
) *dataRef
= NULL
;
163 if (dataLen
) *dataLen
= 0;
170 *dataRef
= (void *)CFDataGetBytePtr(myXml
);
173 *dataLen
= CFDataGetLength(myXml
);
176 kern_return_t status
;
178 *dataLen
= CFDataGetLength(myXml
);
179 status
= vm_allocate(mach_task_self(), (void *)dataRef
, *dataLen
, TRUE
);
180 if (status
!= KERN_SUCCESS
) {
181 SCLog(TRUE
, LOG_ERR
, CFSTR("_SCSerialize(): %s"), mach_error_string(status
));
188 bcopy((char *)CFDataGetBytePtr(myXml
), *dataRef
, *dataLen
);
197 _SCUnserialize(CFPropertyListRef
*obj
, CFDataRef xml
, void *dataRef
, CFIndex dataLen
)
199 CFStringRef xmlError
;
202 kern_return_t status
;
204 xml
= CFDataCreateWithBytesNoCopy(NULL
, (void *)dataRef
, dataLen
, kCFAllocatorNull
);
205 *obj
= CFPropertyListCreateFromXMLData(NULL
,
207 kCFPropertyListImmutable
,
211 status
= vm_deallocate(mach_task_self(), (vm_address_t
)dataRef
, dataLen
);
212 if (status
!= KERN_SUCCESS
) {
213 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("_SCUnserialize(): %s"), mach_error_string(status
));
214 /* non-fatal???, proceed */
217 *obj
= CFPropertyListCreateFromXMLData(NULL
,
219 kCFPropertyListImmutable
,
225 SCLog(TRUE
, LOG_ERR
, CFSTR("_SCUnserialize(): %@"), xmlError
);
228 _SCErrorSet(kSCStatusFailed
);
237 _SCSerializeString(CFStringRef str
, CFDataRef
*data
, void **dataRef
, CFIndex
*dataLen
)
241 if (!isA_CFString(str
)) {
242 /* if not a CFString */
246 if (!data
&& !(dataRef
&& dataLen
)) {
247 /* if not keeping track of allocated space */
251 myData
= CFStringCreateExternalRepresentation(NULL
, str
, kCFStringEncodingUTF8
, 0);
253 SCLog(TRUE
, LOG_ERR
, CFSTR("_SCSerializeString() failed"));
254 if (data
) *data
= NULL
;
255 if (dataRef
) *dataRef
= NULL
;
256 if (dataLen
) *dataLen
= 0;
263 *dataRef
= (void *)CFDataGetBytePtr(myData
);
266 *dataLen
= CFDataGetLength(myData
);
269 kern_return_t status
;
271 *dataLen
= CFDataGetLength(myData
);
272 status
= vm_allocate(mach_task_self(), (void *)dataRef
, *dataLen
, TRUE
);
273 if (status
!= KERN_SUCCESS
) {
274 SCLog(TRUE
, LOG_ERR
, CFSTR("_SCSerializeString(): %s"), mach_error_string(status
));
281 bcopy((char *)CFDataGetBytePtr(myData
), *dataRef
, *dataLen
);
290 _SCUnserializeString(CFStringRef
*str
, CFDataRef utf8
, void *dataRef
, CFIndex dataLen
)
293 kern_return_t status
;
295 utf8
= CFDataCreateWithBytesNoCopy(NULL
, dataRef
, dataLen
, kCFAllocatorNull
);
296 *str
= CFStringCreateFromExternalRepresentation(NULL
, utf8
, kCFStringEncodingUTF8
);
299 status
= vm_deallocate(mach_task_self(), (vm_address_t
)dataRef
, dataLen
);
300 if (status
!= KERN_SUCCESS
) {
301 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("_SCUnserializeString(): %s"), mach_error_string(status
));
302 /* non-fatal???, proceed */
305 *str
= CFStringCreateFromExternalRepresentation(NULL
, utf8
, kCFStringEncodingUTF8
);
309 SCLog(TRUE
, LOG_ERR
, CFSTR("_SCUnserializeString() failed"));
318 _SCSerializeData(CFDataRef data
, void **dataRef
, CFIndex
*dataLen
)
320 kern_return_t status
;
322 if (!isA_CFData(data
)) {
323 /* if not a CFData */
327 *dataLen
= CFDataGetLength(data
);
328 status
= vm_allocate(mach_task_self(), (void *)dataRef
, *dataLen
, TRUE
);
329 if (status
!= KERN_SUCCESS
) {
330 SCLog(TRUE
, LOG_ERR
, CFSTR("_SCSerializeData(): %s"), mach_error_string(status
));
336 bcopy((char *)CFDataGetBytePtr(data
), *dataRef
, *dataLen
);
343 _SCUnserializeData(CFDataRef
*data
, void *dataRef
, CFIndex dataLen
)
345 kern_return_t status
;
347 *data
= CFDataCreate(NULL
, dataRef
, dataLen
);
348 status
= vm_deallocate(mach_task_self(), (vm_address_t
)dataRef
, dataLen
);
349 if (status
!= KERN_SUCCESS
) {
350 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("_SCUnserializeData(): %s"), mach_error_string(status
));
351 _SCErrorSet(kSCStatusFailed
);
360 _SCSerializeMultiple(CFDictionaryRef dict
)
362 const void * keys_q
[N_QUICK
];
363 const void ** keys
= keys_q
;
365 CFDictionaryRef newDict
= NULL
;
366 const void * pLists_q
[N_QUICK
];
367 const void ** pLists
= pLists_q
;
368 const void * values_q
[N_QUICK
];
369 const void ** values
= values_q
;
371 nElements
= CFDictionaryGetCount(dict
);
375 if (nElements
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
376 keys
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
377 values
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
378 pLists
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
380 bzero(pLists
, nElements
* sizeof(CFTypeRef
));
382 CFDictionaryGetKeysAndValues(dict
, keys
, values
);
383 for (i
= 0; i
< nElements
; i
++) {
384 if (!_SCSerialize((CFPropertyListRef
)values
[i
], (CFDataRef
*)&pLists
[i
], NULL
, NULL
)) {
390 newDict
= CFDictionaryCreate(NULL
,
394 &kCFTypeDictionaryKeyCallBacks
,
395 &kCFTypeDictionaryValueCallBacks
);
402 for (i
= 0; i
< nElements
; i
++) {
403 if (pLists
[i
]) CFRelease(pLists
[i
]);
406 if (keys
!= keys_q
) {
407 CFAllocatorDeallocate(NULL
, keys
);
408 CFAllocatorDeallocate(NULL
, values
);
409 CFAllocatorDeallocate(NULL
, pLists
);
418 _SCUnserializeMultiple(CFDictionaryRef dict
)
420 const void * keys_q
[N_QUICK
];
421 const void ** keys
= keys_q
;
423 CFDictionaryRef newDict
= NULL
;
424 const void * pLists_q
[N_QUICK
];
425 const void ** pLists
= pLists_q
;
426 const void * values_q
[N_QUICK
];
427 const void ** values
= values_q
;
429 nElements
= CFDictionaryGetCount(dict
);
433 if (nElements
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
434 keys
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
435 values
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
436 pLists
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
438 bzero(pLists
, nElements
* sizeof(CFTypeRef
));
440 CFDictionaryGetKeysAndValues(dict
, keys
, values
);
441 for (i
= 0; i
< nElements
; i
++) {
442 if (!_SCUnserialize((CFPropertyListRef
*)&pLists
[i
], values
[i
], NULL
, 0)) {
448 newDict
= CFDictionaryCreate(NULL
,
452 &kCFTypeDictionaryKeyCallBacks
,
453 &kCFTypeDictionaryValueCallBacks
);
460 for (i
= 0; i
< nElements
; i
++) {
461 if (pLists
[i
]) CFRelease(pLists
[i
]);
464 if (keys
!= keys_q
) {
465 CFAllocatorDeallocate(NULL
, keys
);
466 CFAllocatorDeallocate(NULL
, values
);
467 CFAllocatorDeallocate(NULL
, pLists
);
475 __private_extern__
void
476 _SC_signalRunLoop(CFTypeRef obj
, CFRunLoopSourceRef rls
, CFArrayRef rlList
)
478 CFRunLoopRef rl
= NULL
;
479 CFRunLoopRef rl1
= NULL
;
481 CFIndex n
= CFArrayGetCount(rlList
);
487 /* get first runLoop for this object */
488 for (i
= 0; i
< n
; i
+= 3) {
489 if (!CFEqual(obj
, CFArrayGetValueAtIndex(rlList
, i
))) {
493 rl1
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlList
, i
+1);
498 /* if not scheduled */
502 /* check if we have another runLoop for this object */
504 for (i
= i
+3; i
< n
; i
+= 3) {
507 if (!CFEqual(obj
, CFArrayGetValueAtIndex(rlList
, i
))) {
511 rl2
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlList
, i
+1);
512 if (!CFEqual(rl1
, rl2
)) {
513 /* we've got more than one runLoop */
520 /* if we only have one runLoop */
525 /* more than one different runLoop, so we must pick one */
526 for (i
= 0; i
< n
; i
+=3) {
529 if (!CFEqual(obj
, CFArrayGetValueAtIndex(rlList
, i
))) {
533 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlList
, i
+1);
534 rlMode
= CFRunLoopCopyCurrentMode(rl
);
535 if (rlMode
&& CFRunLoopIsWaiting(rl
) && CFRunLoopContainsSource(rl
, rls
, rlMode
)) {
536 /* we've found a runLoop that's "ready" */
541 if (rlMode
) CFRelease(rlMode
);
544 /* didn't choose one above, so choose first */
545 CFRunLoopWakeUp(rl1
);
550 __private_extern__ Boolean
551 _SC_isScheduled(CFTypeRef obj
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
, CFMutableArrayRef rlList
)
554 CFIndex n
= CFArrayGetCount(rlList
);
556 for (i
= 0; i
< n
; i
+= 3) {
557 if (obj
&& !CFEqual(obj
, CFArrayGetValueAtIndex(rlList
, i
))) {
560 if (runLoop
&& !CFEqual(runLoop
, CFArrayGetValueAtIndex(rlList
, i
+1))) {
563 if (runLoopMode
&& !CFEqual(runLoopMode
, CFArrayGetValueAtIndex(rlList
, i
+2))) {
573 __private_extern__
void
574 _SC_schedule(CFTypeRef obj
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
, CFMutableArrayRef rlList
)
576 CFArrayAppendValue(rlList
, obj
);
577 CFArrayAppendValue(rlList
, runLoop
);
578 CFArrayAppendValue(rlList
, runLoopMode
);
584 __private_extern__ Boolean
585 _SC_unschedule(CFTypeRef obj
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
, CFMutableArrayRef rlList
, Boolean all
)
588 Boolean found
= FALSE
;
589 CFIndex n
= CFArrayGetCount(rlList
);
592 if (obj
&& !CFEqual(obj
, CFArrayGetValueAtIndex(rlList
, i
))) {
596 if (runLoop
&& !CFEqual(runLoop
, CFArrayGetValueAtIndex(rlList
, i
+1))) {
600 if (runLoopMode
&& !CFEqual(runLoopMode
, CFArrayGetValueAtIndex(rlList
, i
+2))) {
607 CFArrayRemoveValueAtIndex(rlList
, i
+ 2);
608 CFArrayRemoveValueAtIndex(rlList
, i
+ 1);
609 CFArrayRemoveValueAtIndex(rlList
, i
);
623 __showMachPortStatus()
626 /* print status of in-use mach ports */
628 kern_return_t status
;
629 mach_port_name_array_t ports
;
630 mach_port_type_array_t types
;
632 CFMutableStringRef str
;
634 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("----------"));
636 /* report on ALL mach ports associated with this task */
637 status
= mach_port_names(mach_task_self(), &ports
, &pn
, &types
, &tn
);
638 if (status
== MACH_MSG_SUCCESS
) {
639 str
= CFStringCreateMutable(NULL
, 0);
640 for (pi
= 0; pi
< pn
; pi
++) {
641 char rights
[16], *rp
= &rights
[0];
643 if (types
[pi
] != MACH_PORT_TYPE_NONE
) {
646 if (types
[pi
] & MACH_PORT_TYPE_SEND
)
648 if (types
[pi
] & MACH_PORT_TYPE_RECEIVE
)
650 if (types
[pi
] & MACH_PORT_TYPE_SEND_ONCE
)
652 if (types
[pi
] & MACH_PORT_TYPE_PORT_SET
)
654 if (types
[pi
] & MACH_PORT_TYPE_DEAD_NAME
)
659 CFStringAppendFormat(str
, NULL
, CFSTR(" %d%s"), ports
[pi
], rights
);
661 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("Task ports (n=%d):%@"), pn
, str
);
664 /* log (but ignore) errors */
665 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("mach_port_names(): %s"), mach_error_string(status
));
674 __showMachPortReferences(mach_port_t port
)
677 kern_return_t status
;
678 mach_port_urefs_t refs_send
= 0;
679 mach_port_urefs_t refs_recv
= 0;
680 mach_port_urefs_t refs_once
= 0;
681 mach_port_urefs_t refs_pset
= 0;
682 mach_port_urefs_t refs_dead
= 0;
684 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("user references for mach port %d"), port
);
686 status
= mach_port_get_refs(mach_task_self(), port
, MACH_PORT_RIGHT_SEND
, &refs_send
);
687 if (status
!= KERN_SUCCESS
) {
688 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" mach_port_get_refs(MACH_PORT_RIGHT_SEND): %s"), mach_error_string(status
));
692 status
= mach_port_get_refs(mach_task_self(), port
, MACH_PORT_RIGHT_RECEIVE
, &refs_recv
);
693 if (status
!= KERN_SUCCESS
) {
694 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" mach_port_get_refs(MACH_PORT_RIGHT_RECEIVE): %s"), mach_error_string(status
));
698 status
= mach_port_get_refs(mach_task_self(), port
, MACH_PORT_RIGHT_SEND_ONCE
, &refs_once
);
699 if (status
!= KERN_SUCCESS
) {
700 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" mach_port_get_refs(MACH_PORT_RIGHT_SEND_ONCE): %s"), mach_error_string(status
));
704 status
= mach_port_get_refs(mach_task_self(), port
, MACH_PORT_RIGHT_PORT_SET
, &refs_pset
);
705 if (status
!= KERN_SUCCESS
) {
706 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" mach_port_get_refs(MACH_PORT_RIGHT_PORT_SET): %s"), mach_error_string(status
));
710 status
= mach_port_get_refs(mach_task_self(), port
, MACH_PORT_RIGHT_DEAD_NAME
, &refs_dead
);
711 if (status
!= KERN_SUCCESS
) {
712 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" mach_port_get_refs(MACH_PORT_RIGHT_DEAD_NAME): %s"), mach_error_string(status
));
716 SCLog(_sc_verbose
, LOG_DEBUG
,
717 CFSTR(" send = %d, receive = %d, send once = %d, port set = %d, dead name = %d"),