2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
27 * Modification History
29 * December 20, 2002 Christophe Allie <callie@apple.com>
33 /* -------------------------------------------------------------------------------------------
34 ------------------------------------------------------------------------------------------- */
36 #include <CoreFoundation/CoreFoundation.h>
37 #include <CoreFoundation/CFRuntime.h>
39 #include <Security/Security.h>
40 #include "dy_framework.h"
42 #include <SystemConfiguration/SystemConfiguration.h>
43 #include <SystemConfiguration/SCPrivate.h>
44 #include <SystemConfiguration/SCValidation.h>
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
49 #include <arpa/nameser.h>
53 #include <sys/ioctl.h>
54 #include <sys/socket.h>
60 /* -------------------------------------------------------------------------------------------
61 ------------------------------------------------------------------------------------------- */
65 /* base CFType information */
69 CFStringRef serviceID
; /* serviceID */
71 int eventRef
; /* ref to PPP controller for event messages */
72 CFSocketRef eventRefCF
; /* ref to PPP controller for event messages */
73 int controlRef
; /* ref to PPP controller for control messages */
74 //u_int32_t status; /* current status of the connection */
75 //char ifname[IFNAMSIZ]; /* ppp interface used for this connection */
77 /* run loop source, callout, context, rl scheduling info */
78 CFRunLoopSourceRef rls
;
79 SCNetworkConnectionCallBack rlsFunction
;
80 SCNetworkConnectionContext rlsContext
;
81 CFMutableArrayRef rlList
;
83 } SCNetworkConnectionPrivate
, *SCNetworkConnectionPrivateRef
;
85 /* -------------------------------------------------------------------------------------------
86 ------------------------------------------------------------------------------------------- */
88 static __inline__ CFTypeRef
89 isA_SCNetworkConnection(CFTypeRef obj
)
91 return (isA_CFType(obj
, SCNetworkConnectionGetTypeID()));
94 /* -------------------------------------------------------------------------------------------
95 ------------------------------------------------------------------------------------------- */
98 __SCNetworkConnectionCopyDescription(CFTypeRef cf
)
100 CFAllocatorRef allocator
= CFGetAllocator(cf
);
101 CFMutableStringRef result
;
102 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)cf
;
104 result
= CFStringCreateMutable(allocator
, 0);
105 CFStringAppendFormat(result
, NULL
, CFSTR("<SCNetworkConnection, %p [%p]> {\n"), cf
, allocator
);
106 CFStringAppendFormat(result
, NULL
, CFSTR(" serviceID = %@ \n"), connectionPrivate
->serviceID
);
107 CFStringAppendFormat(result
, NULL
, CFSTR("}"));
112 /* -------------------------------------------------------------------------------------------
113 ------------------------------------------------------------------------------------------- */
115 __SCNetworkConnectionDeallocate(CFTypeRef cf
)
117 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)cf
;
119 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("__SCNetworkConnectionDeallocate:"));
121 /* release resources */
122 if (connectionPrivate
->eventRef
!= -1) {
123 while (CFArrayGetCount(connectionPrivate
->rlList
)) {
124 CFRunLoopRef runLoop
;
125 CFStringRef runLoopMode
;
127 runLoop
= (CFRunLoopRef
)CFArrayGetValueAtIndex(connectionPrivate
->rlList
, 1);
128 runLoopMode
= CFArrayGetValueAtIndex(connectionPrivate
->rlList
, 2);
129 CFRunLoopRemoveSource(runLoop
, connectionPrivate
->rls
, runLoopMode
);
131 CFArrayRemoveValueAtIndex(connectionPrivate
->rlList
, 2);
132 CFArrayRemoveValueAtIndex(connectionPrivate
->rlList
, 1);
133 CFArrayRemoveValueAtIndex(connectionPrivate
->rlList
, 0);
135 CFRelease(connectionPrivate
->rls
);
136 CFRelease(connectionPrivate
->rlList
);
137 //PPPDispose(connectionPrivate->eventRef);
138 CFSocketInvalidate(connectionPrivate
->eventRefCF
);
139 CFRelease(connectionPrivate
->eventRefCF
);
141 if (connectionPrivate
->controlRef
!= -1)
142 PPPDispose(connectionPrivate
->controlRef
);
143 if (connectionPrivate
->rlsContext
.release
)
144 connectionPrivate
->rlsContext
.release(connectionPrivate
->rlsContext
.info
);
145 if (connectionPrivate
->serviceID
)
146 CFRelease(connectionPrivate
->serviceID
);
151 /* -------------------------------------------------------------------------------------------
152 ------------------------------------------------------------------------------------------- */
154 static pthread_once_t initialized
= PTHREAD_ONCE_INIT
;
156 static CFTypeID __kSCNetworkConnectionTypeID
= _kCFRuntimeNotATypeID
;
158 static const CFRuntimeClass __SCNetworkConnectionClass
= {
160 "SCNetworkConnection", // className
163 __SCNetworkConnectionDeallocate
, // dealloc
166 NULL
, // copyFormattingDesc
167 __SCNetworkConnectionCopyDescription
// copyDebugDesc
170 /* -------------------------------------------------------------------------------------------
171 ------------------------------------------------------------------------------------------- */
174 __SCNetworkConnectionInitialize(void)
176 __kSCNetworkConnectionTypeID
= _CFRuntimeRegisterClass(&__SCNetworkConnectionClass
);
180 /* -------------------------------------------------------------------------------------------
181 ------------------------------------------------------------------------------------------- */
182 static SCNetworkConnectionPrivateRef
183 __SCNetworkConnectionCreatePrivate(CFAllocatorRef allocator
, CFStringRef serviceID
)
185 SCNetworkConnectionPrivateRef connectionPrivate
= 0;
187 struct ppp_status
*stats
= 0;
188 int error
= kSCStatusFailed
;
190 /* initialize runtime */
191 pthread_once(&initialized
, __SCNetworkConnectionInitialize
);
193 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("__SCNetworkConnectionCreatePrivate:"));
195 /* allocate NetworkConnection */
196 size
= sizeof(SCNetworkConnectionPrivate
) - sizeof(CFRuntimeBase
);
197 connectionPrivate
= (SCNetworkConnectionPrivateRef
)_CFRuntimeCreateInstance(allocator
, __kSCNetworkConnectionTypeID
,size
, NULL
);
198 if (connectionPrivate
== 0)
201 /* zero the data structure */
202 bzero(((u_char
*)connectionPrivate
)+sizeof(CFRuntimeBase
), size
);
204 /* save the serviceID */
205 connectionPrivate
->serviceID
= CFStringCreateCopy(NULL
, serviceID
);
207 connectionPrivate
->controlRef
= -1;
208 connectionPrivate
->eventRef
= -1;
210 if (PPPInit(&connectionPrivate
->controlRef
))
213 if (PPPStatus(connectionPrivate
->controlRef
, serviceID
, 0, &stats
)) {
214 error
= kSCStatusInvalidArgument
; // XXX can't get status, invalid service id
218 CFAllocatorDeallocate(NULL
, stats
);
221 /* success, return the connection reference */
222 return connectionPrivate
;
226 /* failure, clean up and leave */
227 if (connectionPrivate
)
228 CFRelease(connectionPrivate
);
230 CFAllocatorDeallocate(NULL
, stats
);
235 /* -------------------------------------------------------------------------------------------
236 ------------------------------------------------------------------------------------------- */
239 SCNetworkConnectionGetTypeID (void) {
240 pthread_once(&initialized
, __SCNetworkConnectionInitialize
); /* initialize runtime */
241 return __kSCNetworkConnectionTypeID
;
244 /* -------------------------------------------------------------------------------------------
245 ------------------------------------------------------------------------------------------- */
246 static SCNetworkConnectionStatus
247 __SCNetworkConnectionConvertStatus (int state
)
249 SCNetworkConnectionStatus status
= kSCNetworkConnectionDisconnected
;
253 case PPP_CONNECTLINK
:
255 case PPP_AUTHENTICATE
:
259 status
= kSCNetworkConnectionConnecting
;
262 case PPP_DISCONNECTLINK
:
264 status
= kSCNetworkConnectionDisconnecting
;
268 status
= kSCNetworkConnectionConnected
;
271 case PPP_STATERESERVED
:
273 status
= kSCNetworkConnectionDisconnected
;
278 /* -------------------------------------------------------------------------------------------
279 ------------------------------------------------------------------------------------------- */
281 SCNetworkConnectionRef
282 SCNetworkConnectionCreateWithServiceID (CFAllocatorRef allocator
,
283 CFStringRef serviceID
,
284 SCNetworkConnectionCallBack callout
,
285 SCNetworkConnectionContext
*context
)
287 SCNetworkConnectionPrivateRef connectionPrivate
;
289 if (!isA_CFString(serviceID
)) {
290 _SCErrorSet(kSCStatusInvalidArgument
);
294 connectionPrivate
= __SCNetworkConnectionCreatePrivate(allocator
, serviceID
);
296 if (connectionPrivate
) {
297 connectionPrivate
->rlsFunction
= callout
;
299 bcopy(context
, &connectionPrivate
->rlsContext
, sizeof(SCNetworkConnectionContext
));
300 if (context
->retain
) {
301 connectionPrivate
->rlsContext
.info
= (void *)context
->retain(context
->info
);
306 return (SCNetworkConnectionRef
)connectionPrivate
;
309 /* -------------------------------------------------------------------------------------------
310 ------------------------------------------------------------------------------------------- */
313 SCNetworkConnectionCopyServiceID (SCNetworkConnectionRef connection
)
315 if (!isA_SCNetworkConnection(connection
)) {
316 _SCErrorSet(kSCStatusInvalidArgument
);
320 return CFRetain(((SCNetworkConnectionPrivateRef
)connection
)->serviceID
);
323 /* -------------------------------------------------------------------------------------------
324 ------------------------------------------------------------------------------------------- */
327 SCNetworkConnectionCopyStatistics (SCNetworkConnectionRef connection
)
329 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
330 int error
= kSCStatusFailed
;
331 struct ppp_status
*stats
= 0;
332 CFMutableDictionaryRef dict
= 0;
333 CFMutableDictionaryRef statsdict
= 0;
335 #define ADDNUMBER(d, k, n) \
338 num = CFNumberCreate(NULL, kCFNumberSInt32Type, n); \
340 CFDictionaryAddValue(d, k, num); \
345 if (!isA_SCNetworkConnection(connection
)) {
346 _SCErrorSet(kSCStatusInvalidArgument
);
350 /* get status and check connected state */
351 if (PPPStatus(connectionPrivate
->controlRef
, connectionPrivate
->serviceID
, 0, &stats
))
354 if (__SCNetworkConnectionConvertStatus(stats
->status
) != kSCNetworkConnectionConnected
)
357 /* create dictionaries */
358 if ((statsdict
= CFDictionaryCreateMutable(NULL
, 0, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
)) == 0)
361 if ((dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
)) == 0)
365 ADDNUMBER(dict
, kSCNetworkConnectionBytesIn
, &stats
->s
.run
.inBytes
);
366 ADDNUMBER(dict
, kSCNetworkConnectionBytesOut
, &stats
->s
.run
.outBytes
);
367 ADDNUMBER(dict
, kSCNetworkConnectionPacketsIn
, &stats
->s
.run
.inPackets
);
368 ADDNUMBER(dict
, kSCNetworkConnectionPacketsOut
, &stats
->s
.run
.outPackets
);
369 ADDNUMBER(dict
, kSCNetworkConnectionErrorsIn
, &stats
->s
.run
.inErrors
);
370 ADDNUMBER(dict
, kSCNetworkConnectionErrorsOut
, &stats
->s
.run
.outErrors
);
372 /* add the PPP dictionary to the statistics dictionary */
373 CFDictionaryAddValue(statsdict
, kSCEntNetPPP
, dict
);
377 CFAllocatorDeallocate(NULL
, stats
);
383 CFAllocatorDeallocate(NULL
, stats
);
387 CFRelease(statsdict
);
392 /* -------------------------------------------------------------------------------------------
393 ------------------------------------------------------------------------------------------- */
395 SCNetworkConnectionStatus
396 SCNetworkConnectionGetStatus (SCNetworkConnectionRef connection
)
398 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
399 struct ppp_status
*stats
= 0;
400 SCNetworkConnectionStatus status
;
402 if (!isA_SCNetworkConnection(connection
)) {
403 _SCErrorSet(kSCStatusInvalidArgument
);
407 if (PPPStatus(connectionPrivate
->controlRef
, connectionPrivate
->serviceID
, 0, &stats
))
408 return kSCNetworkConnectionDisconnected
; // XXX
410 status
= __SCNetworkConnectionConvertStatus(stats
->status
);
412 CFAllocatorDeallocate(NULL
, stats
);
416 /* -------------------------------------------------------------------------------------------
417 ------------------------------------------------------------------------------------------- */
419 SCNetworkConnectionCopyExtendedStatus (SCNetworkConnectionRef connection
)
421 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
422 CFPropertyListRef status
= 0;
426 if (!isA_SCNetworkConnection(connection
)) {
427 _SCErrorSet(kSCStatusInvalidArgument
);
431 if (PPPExtendedStatus(connectionPrivate
->controlRef
, connectionPrivate
->serviceID
, 0, &data
, &datalen
))
435 || !(status
= PPPUnserialize(data
, datalen
))
436 || !isA_CFDictionary(status
))
439 CFAllocatorDeallocate(NULL
, data
);
444 _SCErrorSet(kSCStatusFailed
);
448 CFAllocatorDeallocate(NULL
, data
);
452 /* -------------------------------------------------------------------------------------------
453 ------------------------------------------------------------------------------------------- */
456 SCNetworkConnectionStart (SCNetworkConnectionRef connection
,
457 CFDictionaryRef userOptions
,
460 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
461 CFDataRef dataref
= 0;
463 u_int32_t datalen
= 0;
465 if (!isA_SCNetworkConnection(connection
)) {
466 _SCErrorSet(kSCStatusInvalidArgument
);
470 if (userOptions
&& !(dataref
= PPPSerialize(userOptions
, &data
, &datalen
)))
473 if (PPPConnect(connectionPrivate
->controlRef
, connectionPrivate
->serviceID
, 0, data
, datalen
, linger
))
479 /* connection is now started */
486 _SCErrorSet(kSCStatusFailed
); // XXX
490 /* -------------------------------------------------------------------------------------------
491 ------------------------------------------------------------------------------------------- */
494 SCNetworkConnectionStop (SCNetworkConnectionRef connection
,
495 Boolean forceDisconnect
)
497 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
499 if (!isA_SCNetworkConnection(connection
)) {
500 _SCErrorSet(kSCStatusInvalidArgument
);
504 if (PPPDisconnect(connectionPrivate
->controlRef
, connectionPrivate
->serviceID
, 0, forceDisconnect
)) {
505 _SCErrorSet(kSCStatusFailed
);
509 /* connection is now disconnecting */
513 /* -------------------------------------------------------------------------------------------
514 ------------------------------------------------------------------------------------------- */
517 SCNetworkConnectionSuspend (SCNetworkConnectionRef connection
)
519 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
521 if (!isA_SCNetworkConnection(connection
)) {
522 _SCErrorSet(kSCStatusInvalidArgument
);
526 if (PPPSuspend(connectionPrivate
->controlRef
, connectionPrivate
->serviceID
, 0)) {
527 _SCErrorSet(kSCStatusFailed
);
531 /* connection is now suspended */
535 /* -------------------------------------------------------------------------------------------
536 ------------------------------------------------------------------------------------------- */
539 SCNetworkConnectionResume (SCNetworkConnectionRef connection
)
541 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
543 if (!isA_SCNetworkConnection(connection
)) {
544 _SCErrorSet(kSCStatusInvalidArgument
);
548 if (PPPResume(connectionPrivate
->controlRef
, connectionPrivate
->serviceID
, 0)) {
549 _SCErrorSet(kSCStatusFailed
);
553 /* connection is now resume */
557 /* -------------------------------------------------------------------------------------------
558 ------------------------------------------------------------------------------------------- */
561 SCNetworkConnectionCopyUserOptions (SCNetworkConnectionRef connection
)
563 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
566 CFPropertyListRef userOptions
= 0;
568 if (!isA_SCNetworkConnection(connection
)) {
569 _SCErrorSet(kSCStatusInvalidArgument
);
573 if (PPPGetConnectData(connectionPrivate
->controlRef
, connectionPrivate
->serviceID
, 0, &data
, &datalen
))
576 // no data were used, return an empty dictionary
578 CFDictionaryRef dict
;
580 dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
582 _SCErrorSet(kSCStatusFailed
); // XXX
586 userOptions
= PPPUnserialize(data
, datalen
);
587 if (!isA_CFDictionary(userOptions
))
590 CFAllocatorDeallocate(NULL
, data
);
595 _SCErrorSet(kSCStatusFailed
);
597 CFRelease(userOptions
);
599 CFAllocatorDeallocate(NULL
, data
);
603 /* -------------------------------------------------------------------------------------------
604 ------------------------------------------------------------------------------------------- */
607 __isScheduled(CFTypeRef obj
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
, CFMutableArrayRef rlList
)
610 CFIndex n
= CFArrayGetCount(rlList
);
612 for (i
= 0; i
< n
; i
+= 3) {
613 if (obj
&& !CFEqual(obj
, CFArrayGetValueAtIndex(rlList
, i
))) {
616 if (runLoop
&& !CFEqual(runLoop
, CFArrayGetValueAtIndex(rlList
, i
+1))) {
619 if (runLoopMode
&& !CFEqual(runLoopMode
, CFArrayGetValueAtIndex(rlList
, i
+2))) {
628 /* -------------------------------------------------------------------------------------------
629 ------------------------------------------------------------------------------------------- */
631 __schedule(CFTypeRef obj
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
, CFMutableArrayRef rlList
)
633 CFArrayAppendValue(rlList
, obj
);
634 CFArrayAppendValue(rlList
, runLoop
);
635 CFArrayAppendValue(rlList
, runLoopMode
);
640 /* -------------------------------------------------------------------------------------------
641 ------------------------------------------------------------------------------------------- */
643 __unschedule(CFTypeRef obj
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
, CFMutableArrayRef rlList
, Boolean all
)
646 Boolean found
= FALSE
;
647 CFIndex n
= CFArrayGetCount(rlList
);
650 if (obj
&& !CFEqual(obj
, CFArrayGetValueAtIndex(rlList
, i
))) {
654 if (runLoop
&& !CFEqual(runLoop
, CFArrayGetValueAtIndex(rlList
, i
+1))) {
658 if (runLoopMode
&& !CFEqual(runLoopMode
, CFArrayGetValueAtIndex(rlList
, i
+2))) {
665 CFArrayRemoveValueAtIndex(rlList
, i
+ 2);
666 CFArrayRemoveValueAtIndex(rlList
, i
+ 1);
667 CFArrayRemoveValueAtIndex(rlList
, i
);
679 /* -------------------------------------------------------------------------------------------
680 ------------------------------------------------------------------------------------------- */
683 __SCNetworkConnectionCallBack(CFSocketRef inref
,
684 CFSocketCallBackType type
,
690 void (*context_release
)(const void *);
691 SCNetworkConnectionRef connection
= (SCNetworkConnectionRef
)info
;
692 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
693 SCNetworkConnectionCallBack rlsFunction
;
694 SCNetworkConnectionStatus status
;
698 err
= PPPReadEvent(connectionPrivate
->eventRef
, &pppstatus
);
702 rlsFunction
= connectionPrivate
->rlsFunction
;
703 if (connectionPrivate
->rlsContext
.retain
&& connectionPrivate
->rlsContext
.info
) {
704 context_info
= (void *)connectionPrivate
->rlsContext
.retain(connectionPrivate
->rlsContext
.info
);
705 context_release
= connectionPrivate
->rlsContext
.release
;
708 context_info
= connectionPrivate
->rlsContext
.info
;
709 context_release
= NULL
;
712 status
= __SCNetworkConnectionConvertStatus(pppstatus
);
714 (*rlsFunction
)(connection
, status
, context_info
);
715 if (context_release
&& context_info
) {
716 context_release(context_info
);
720 /* -------------------------------------------------------------------------------------------
721 ------------------------------------------------------------------------------------------- */
724 SCNetworkConnectionScheduleWithRunLoop(SCNetworkConnectionRef connection
,
725 CFRunLoopRef runLoop
,
726 CFStringRef runLoopMode
)
728 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
731 if (!isA_SCNetworkConnection(connection
) || runLoop
== NULL
|| runLoopMode
== NULL
) {
732 _SCErrorSet(kSCStatusInvalidArgument
);
736 if (connectionPrivate
->rlsFunction
== 0) {
737 _SCErrorSet(kSCStatusInvalidArgument
);
741 if (connectionPrivate
->rlList
742 && __isScheduled(NULL
, runLoop
, runLoopMode
, connectionPrivate
->rlList
)) {
743 /* already scheduled */
744 _SCErrorSet(kSCStatusFailed
);
748 if (connectionPrivate
->eventRef
== -1) {
749 CFSocketContext context
= { 0, (void*)connection
, CFRetain
, CFRelease
, CFCopyDescription
};
751 if (PPPInit(&connectionPrivate
->eventRef
)) {
752 _SCErrorSet(kSCStatusFailed
);
756 PPPEnableEvents(connectionPrivate
->eventRef
, connectionPrivate
->serviceID
, 0, 1);
758 connectionPrivate
->eventRefCF
= CFSocketCreateWithNative(NULL
, connectionPrivate
->eventRef
,
759 kCFSocketReadCallBack
, __SCNetworkConnectionCallBack
, &context
);
760 connectionPrivate
->rls
= CFSocketCreateRunLoopSource(NULL
, connectionPrivate
->eventRefCF
, 0);
761 connectionPrivate
->rlList
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
766 CFRunLoopAddSource(runLoop
, connectionPrivate
->rls
, runLoopMode
);
767 __schedule(connectionPrivate
, runLoop
, runLoopMode
, connectionPrivate
->rlList
);
772 /* -------------------------------------------------------------------------------------------
773 ------------------------------------------------------------------------------------------- */
776 SCNetworkConnectionUnscheduleFromRunLoop(SCNetworkConnectionRef connection
,
777 CFRunLoopRef runLoop
,
778 CFStringRef runLoopMode
)
780 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
782 if (!isA_SCNetworkConnection(connection
) || runLoop
== NULL
|| runLoopMode
== NULL
) {
783 _SCErrorSet(kSCStatusInvalidArgument
);
787 if (connectionPrivate
->rlList
== NULL
788 || !__unschedule(connectionPrivate
, runLoop
, runLoopMode
, connectionPrivate
->rlList
, FALSE
)) {
789 /* if not currently scheduled */
790 _SCErrorSet(kSCStatusFailed
);
794 CFRunLoopRemoveSource(runLoop
, connectionPrivate
->rls
, runLoopMode
);
796 if (CFArrayGetCount(connectionPrivate
->rlList
) == 0) {
797 CFRelease(connectionPrivate
->rls
);
798 connectionPrivate
->rls
= NULL
;
799 CFRelease(connectionPrivate
->rlList
);
800 connectionPrivate
->rlList
= NULL
;
801 //PPPDispose(connectionPrivate->eventRef);
802 CFSocketInvalidate(connectionPrivate
->eventRefCF
);
803 CFRelease(connectionPrivate
->eventRefCF
);
804 connectionPrivate
->eventRefCF
= 0;
805 connectionPrivate
->eventRef
= -1;
812 //************************* USER LEVEL DIAL API **********************************
815 #define k_NetworkConnect_Pref_File CFSTR("com.apple.networkConnect")
816 #define k_InterentConnect_Pref_File CFSTR("com.apple.internetconnect")
818 #define k_Dial_Default_Key CFSTR("ConnectByDefault") // needs to go into SC
819 #define k_Last_Service_Id_Key CFSTR("ServiceID")
820 #define k_Unique_Id_Key CFSTR("UniqueIdentifier")
823 /* Private Prototypes */
824 static Boolean
SCNetworkConnectionPrivateCopyDefaultServiceIDForDial (SCDynamicStoreRef session
, CFStringRef
*serviceID
);
825 static Boolean
SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore (SCDynamicStoreRef session
, CFStringRef
*serviceID
);
826 static Boolean
SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray(CFArrayRef userOptionsArray
, CFDictionaryRef
*userOptions
);
827 static Boolean
SCNetworkConnectionPrivateIsPPPService (SCDynamicStoreRef session
, CFStringRef serviceID
);
828 static void addPasswordFromKeychain(CFDictionaryRef
*userOptions
);
829 static CFArrayRef
copyKeychainEnumerator(CFStringRef uniqueIdentifier
);
832 SCNetworkConnectionCopyUserPreferences (CFDictionaryRef selectionOptions
,
833 CFStringRef
*serviceID
,
834 CFDictionaryRef
*userOptions
)
836 SCDynamicStoreRef session
= SCDynamicStoreCreate(NULL
, CFSTR("SCNetworkConnection"), NULL
, NULL
);
837 Boolean success
= FALSE
;
839 // NOTE: we are currently ignoring selectionOptions
841 if (session
!= NULL
) {
842 // (1) Figure out which service ID we care about, allocate it into passed "serviceID"
843 success
= SCNetworkConnectionPrivateCopyDefaultServiceIDForDial(session
, serviceID
);
845 if (success
&& (*serviceID
!= NULL
)) {
846 // (2) Get the list of user data for this service ID
847 CFPropertyListRef userServices
= CFPreferencesCopyValue(*serviceID
,
848 k_NetworkConnect_Pref_File
,
849 kCFPreferencesCurrentUser
,
850 kCFPreferencesCurrentHost
);
852 // (3) We are expecting an array if the user has defined records for this service ID or NULL if the user hasn't
853 if (userServices
!= NULL
) {
854 if (isA_CFArray(userServices
)) {
855 // (4) Get the default set of user options for this service
856 success
= SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray(
857 (CFArrayRef
)userServices
,
859 if(success
&& userOptions
!= NULL
)
861 addPasswordFromKeychain(userOptions
);
864 fprintf(stderr
, "Error, userServices are not of type CFArray!\n");
867 CFRelease(userServices
); // this is OK because SCNetworkConnectionPrivateISExpectedCFType() checks for NULL
873 fprintf(stderr
, "Error, SCNetworkConnectionCopyUserPreferences, SCDynamicStoreCreate() returned NULL!\n");
879 //*******************************************************************************************
880 // SCNetworkConnectionPrivateCopyDefaultServiceIDForDial
881 // ----------------------------------------------------
882 // Try to find the service id to connect
883 // (1) Start by looking at the last service used in Internet Connect
884 // (2) If Internet Connect has not been used, find the PPP service with the highest ordering
885 //********************************************************************************************
887 SCNetworkConnectionPrivateCopyDefaultServiceIDForDial(SCDynamicStoreRef session
, CFStringRef
*serviceID
)
889 Boolean foundService
= FALSE
;
890 CFPropertyListRef lastServiceSelectedInIC
= NULL
;
892 // NULL out the pointer
895 // read out the last service from the Internet Connect preference file
896 lastServiceSelectedInIC
= CFPreferencesCopyValue(k_Last_Service_Id_Key
,
897 k_InterentConnect_Pref_File
,
898 kCFPreferencesCurrentUser
,
899 kCFPreferencesAnyHost
);
901 // we found the service the user last had open in IC
902 if (lastServiceSelectedInIC
!= NULL
) {
903 // make sure its a PPP service
904 if (SCNetworkConnectionPrivateIsPPPService(session
, lastServiceSelectedInIC
)) {
905 // make sure the service that we found is valid
906 CFDictionaryRef dict
;
909 key
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
910 kSCDynamicStoreDomainSetup
,
911 lastServiceSelectedInIC
,
913 dict
= SCDynamicStoreCopyValue(session
, key
);
916 *serviceID
= CFRetain(lastServiceSelectedInIC
);
921 CFRelease(lastServiceSelectedInIC
);
925 foundService
= SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore(session
, serviceID
);
931 //********************************************************************************
932 // SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore
933 // -------------------------------------------------------
934 // Find the highest ordered PPP service in the dynamic store
935 //********************************************************************************
937 SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore(SCDynamicStoreRef session
, CFStringRef
*serviceID
)
939 Boolean success
= FALSE
;
940 CFStringRef key
= NULL
;
941 CFDictionaryRef dict
= NULL
;
942 CFArrayRef serviceIDs
= NULL
;
950 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainSetup
, kSCEntNetIPv4
);
952 fprintf(stderr
, "Error, Setup Key == NULL!\n");
956 dict
= SCDynamicStoreCopyValue(session
, key
);
958 fprintf(stderr
, "Error, Dictionary for setup key == NULL!\n");
962 serviceIDs
= CFDictionaryGetValue(dict
, kSCPropNetServiceOrder
); // array of service id's
963 if (isA_CFArray(serviceIDs
) == NULL
) {
964 if (serviceIDs
== NULL
)
965 fprintf(stderr
, "Error, Array of service IDs == NULL!\n");
967 fprintf(stderr
, "Error, serviceIds are not of type CFArray!\n");
971 count
= CFArrayGetCount(serviceIDs
);
972 for (i
= 0; i
< count
; i
++) {
973 CFStringRef service
= CFArrayGetValueAtIndex(serviceIDs
, i
);
975 if (SCNetworkConnectionPrivateIsPPPService(session
, service
)) {
976 *serviceID
= CFRetain(service
);
992 //********************************************************************************
993 // SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray
994 // ---------------------------------------------------------
995 // Copy over user preferences for a particular service if they exist
996 //********************************************************************************
998 SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray(CFArrayRef userOptionsArray
, CFDictionaryRef
*userOptions
)
1000 CFIndex count
= CFArrayGetCount(userOptionsArray
);
1003 *userOptions
= NULL
;
1005 for (i
= 0; i
< count
; i
++) {
1006 // (1) Find the dictionary
1007 CFPropertyListRef propertyList
= CFArrayGetValueAtIndex(userOptionsArray
, i
);
1009 if (isA_CFDictionary(propertyList
) != NULL
) {
1010 // See if there's a value for dial on demand
1011 CFPropertyListRef value
= CFDictionaryGetValue((CFDictionaryRef
)propertyList
,
1012 k_Dial_Default_Key
);
1013 if (isA_CFBoolean(value
) != NULL
) {
1014 if (CFBooleanGetValue(value
)) {
1015 // we found the default user options
1016 *userOptions
= CFDictionaryCreateCopy(NULL
,
1017 (CFDictionaryRef
)propertyList
);
1027 //********************************************************************************
1028 // SCNetworkConnectionPrivateIsPPPService
1029 // --------------------------------------
1030 // Check and see if the service is a PPP service
1031 //********************************************************************************
1033 SCNetworkConnectionPrivateIsPPPService(SCDynamicStoreRef session
, CFStringRef serviceID
)
1035 CFStringRef entityKey
;
1036 Boolean isPPPService
= FALSE
;
1037 Boolean isModemOrPPPoE
= FALSE
;
1039 entityKey
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1040 kSCDynamicStoreDomainSetup
,
1042 kSCEntNetInterface
);
1043 if (entityKey
!= NULL
) {
1044 CFDictionaryRef serviceDict
;
1046 serviceDict
= SCDynamicStoreCopyValue(session
, entityKey
);
1047 if (serviceDict
!= NULL
) {
1048 if (isA_CFDictionary(serviceDict
)) {
1050 CFStringRef subtype
;
1052 type
= CFDictionaryGetValue(serviceDict
, kSCPropNetInterfaceType
);
1053 if (isA_CFString(type
)) {
1054 isPPPService
= CFEqual(type
, kSCValNetInterfaceTypePPP
);
1057 subtype
= CFDictionaryGetValue(serviceDict
, kSCPropNetInterfaceSubType
);
1058 if (isA_CFString(subtype
)) {
1059 isModemOrPPPoE
= (CFEqual(subtype
, kSCValNetInterfaceSubTypePPPSerial
) ||
1060 CFEqual(subtype
, kSCValNetInterfaceSubTypePPPoE
));
1063 CFRelease(serviceDict
);
1065 CFRelease(entityKey
);
1068 return (isPPPService
&& isModemOrPPPoE
);
1071 //********************************************************************************
1072 // addPasswordFromKeychain
1073 // --------------------------------------
1074 // Get the password out of the keychain and add it to the PPP dictionary
1075 //********************************************************************************
1077 addPasswordFromKeychain(CFDictionaryRef
*userOptions
)
1079 CFArrayRef enumerator
;
1081 CFDictionaryRef oldDict
;
1082 CFPropertyListRef uniqueID
= NULL
;
1084 oldDict
= *userOptions
;
1085 if(oldDict
== NULL
) {
1086 return; // if no userOptions
1089 uniqueID
= CFDictionaryGetValue(oldDict
, k_Unique_Id_Key
);
1090 if(!isA_CFString(uniqueID
)) {
1091 return; // if no unique ID
1094 enumerator
= copyKeychainEnumerator(uniqueID
);
1095 if(enumerator
== NULL
) {
1096 return; // if no keychain enumerator
1100 n
= CFArrayGetCount(enumerator
);
1104 SecKeychainItemRef itemRef
;
1107 itemRef
= (SecKeychainItemRef
)CFArrayGetValueAtIndex(enumerator
, 0);
1108 result
= SecKeychainItemCopyContent(itemRef
, // itemRef
1112 (void *)&data
); // outData
1113 if(result
== noErr
&& data
!= NULL
&& dataLen
> 0) {
1116 pass
= CFStringCreateWithBytes(NULL
, data
, dataLen
, kCFStringEncodingUTF8
, TRUE
);
1118 CFMutableDictionaryRef newDict
;
1119 CFMutableDictionaryRef newPPP
;
1120 CFDictionaryRef pppDict
;
1122 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, oldDict
);
1123 pppDict
= CFDictionaryGetValue(newDict
, kSCEntNetPPP
);
1124 if (isA_CFDictionary(pppDict
)) {
1125 newPPP
= CFDictionaryCreateMutableCopy(NULL
, 0, pppDict
);
1127 newPPP
= CFDictionaryCreateMutable(NULL
,
1129 &kCFTypeDictionaryKeyCallBacks
,
1130 &kCFTypeDictionaryValueCallBacks
);
1133 // set the PPP password
1134 CFDictionarySetValue(newPPP
, kSCPropNetPPPAuthPassword
, pass
);
1137 // update the PPP entity
1138 CFDictionarySetValue(newDict
, kSCEntNetPPP
, newPPP
);
1141 // update the userOptions dictionary
1143 *userOptions
= CFDictionaryCreateCopy(NULL
, newDict
);
1149 CFRelease(enumerator
);
1153 //********************************************************************************
1154 // copyKeychainEnumerator
1155 // --------------------------------------
1156 // Gather Keychain Enumerator
1157 //********************************************************************************
1159 copyKeychainEnumerator(CFStringRef uniqueIdentifier
)
1162 CFMutableArrayRef itemArray
= NULL
;
1164 SecKeychainSearchRef search
= NULL
;
1166 buf
= _SC_cfstring_to_cstring(uniqueIdentifier
, NULL
, 0, kCFStringEncodingUTF8
);
1168 // search for unique identifier in "svce" attribute
1169 SecKeychainAttribute attributes
[] = {{ kSecServiceItemAttr
,
1170 CFStringGetLength(uniqueIdentifier
),
1174 SecKeychainAttributeList attrList
= { sizeof(attributes
) / sizeof(*attributes
),
1177 result
= SecKeychainSearchCreateFromAttributes(NULL
, kSecGenericPasswordItemClass
, &attrList
, &search
);
1178 if (result
== noErr
) {
1179 itemArray
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1181 while (result
== noErr
) {
1182 SecKeychainItemRef itemFound
= NULL
;
1184 result
= SecKeychainSearchCopyNext(search
, &itemFound
);
1185 if (result
!= noErr
) {
1190 CFArrayAppendValue(itemArray
, itemFound
);
1191 CFRelease(itemFound
);
1197 if (search
) CFRelease(search
);
1198 if (buf
) CFAllocatorDeallocate(NULL
, buf
);