2 * Copyright (c) 2002-2003 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 * December 20, 2002 Christophe Allie <callie@apple.com>
31 /* -------------------------------------------------------------------------------------------
32 ------------------------------------------------------------------------------------------- */
34 #include <CoreFoundation/CoreFoundation.h>
35 #include <CoreFoundation/CFRuntime.h>
37 #include <Security/Security.h>
38 #include "dy_framework.h"
40 #include <SystemConfiguration/SystemConfiguration.h>
41 #include <SystemConfiguration/SCPrivate.h>
42 #include <SystemConfiguration/SCValidation.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
47 #include <arpa/nameser.h>
51 #include <sys/ioctl.h>
52 #include <sys/socket.h>
58 /* -------------------------------------------------------------------------------------------
59 ------------------------------------------------------------------------------------------- */
63 /* base CFType information */
67 CFStringRef serviceID
; /* serviceID */
69 int eventRef
; /* ref to PPP controller for event messages */
70 CFSocketRef eventRefCF
; /* ref to PPP controller for event messages */
71 int controlRef
; /* ref to PPP controller for control messages */
72 //u_int32_t status; /* current status of the connection */
73 //char ifname[IFNAMSIZ]; /* ppp interface used for this connection */
75 /* run loop source, callout, context, rl scheduling info */
76 CFRunLoopSourceRef rls
;
77 SCNetworkConnectionCallBack rlsFunction
;
78 SCNetworkConnectionContext rlsContext
;
79 CFMutableArrayRef rlList
;
81 } SCNetworkConnectionPrivate
, *SCNetworkConnectionPrivateRef
;
83 /* -------------------------------------------------------------------------------------------
84 ------------------------------------------------------------------------------------------- */
86 static __inline__ CFTypeRef
87 isA_SCNetworkConnection(CFTypeRef obj
)
89 return (isA_CFType(obj
, SCNetworkConnectionGetTypeID()));
92 /* -------------------------------------------------------------------------------------------
93 ------------------------------------------------------------------------------------------- */
96 __SCNetworkConnectionCopyDescription(CFTypeRef cf
)
98 CFAllocatorRef allocator
= CFGetAllocator(cf
);
99 CFMutableStringRef result
;
100 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)cf
;
102 result
= CFStringCreateMutable(allocator
, 0);
103 CFStringAppendFormat(result
, NULL
, CFSTR("<SCNetworkConnection, %p [%p]> {\n"), cf
, allocator
);
104 CFStringAppendFormat(result
, NULL
, CFSTR(" serviceID = %@ \n"), connectionPrivate
->serviceID
);
105 CFStringAppendFormat(result
, NULL
, CFSTR("}"));
110 /* -------------------------------------------------------------------------------------------
111 ------------------------------------------------------------------------------------------- */
113 __SCNetworkConnectionDeallocate(CFTypeRef cf
)
115 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)cf
;
117 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("__SCNetworkConnectionDeallocate:"));
119 /* release resources */
120 if (connectionPrivate
->eventRef
!= -1) {
121 while (CFArrayGetCount(connectionPrivate
->rlList
)) {
122 CFRunLoopRef runLoop
;
123 CFStringRef runLoopMode
;
125 runLoop
= (CFRunLoopRef
)CFArrayGetValueAtIndex(connectionPrivate
->rlList
, 1);
126 runLoopMode
= CFArrayGetValueAtIndex(connectionPrivate
->rlList
, 2);
127 CFRunLoopRemoveSource(runLoop
, connectionPrivate
->rls
, runLoopMode
);
129 CFArrayRemoveValueAtIndex(connectionPrivate
->rlList
, 2);
130 CFArrayRemoveValueAtIndex(connectionPrivate
->rlList
, 1);
131 CFArrayRemoveValueAtIndex(connectionPrivate
->rlList
, 0);
133 CFRelease(connectionPrivate
->rls
);
134 CFRelease(connectionPrivate
->rlList
);
135 //PPPDispose(connectionPrivate->eventRef);
136 CFSocketInvalidate(connectionPrivate
->eventRefCF
);
137 CFRelease(connectionPrivate
->eventRefCF
);
139 if (connectionPrivate
->controlRef
!= -1)
140 PPPDispose(connectionPrivate
->controlRef
);
141 if (connectionPrivate
->rlsContext
.release
)
142 connectionPrivate
->rlsContext
.release(connectionPrivate
->rlsContext
.info
);
143 if (connectionPrivate
->serviceID
)
144 CFRelease(connectionPrivate
->serviceID
);
149 /* -------------------------------------------------------------------------------------------
150 ------------------------------------------------------------------------------------------- */
152 static pthread_once_t initialized
= PTHREAD_ONCE_INIT
;
154 static CFTypeID __kSCNetworkConnectionTypeID
= _kCFRuntimeNotATypeID
;
156 static const CFRuntimeClass __SCNetworkConnectionClass
= {
158 "SCNetworkConnection", // className
161 __SCNetworkConnectionDeallocate
, // dealloc
164 NULL
, // copyFormattingDesc
165 __SCNetworkConnectionCopyDescription
// copyDebugDesc
168 /* -------------------------------------------------------------------------------------------
169 ------------------------------------------------------------------------------------------- */
172 __SCNetworkConnectionInitialize(void)
174 __kSCNetworkConnectionTypeID
= _CFRuntimeRegisterClass(&__SCNetworkConnectionClass
);
178 /* -------------------------------------------------------------------------------------------
179 ------------------------------------------------------------------------------------------- */
180 static SCNetworkConnectionPrivateRef
181 __SCNetworkConnectionCreatePrivate(CFAllocatorRef allocator
, CFStringRef serviceID
)
183 SCNetworkConnectionPrivateRef connectionPrivate
= 0;
185 struct ppp_status
*stats
= 0;
186 int error
= kSCStatusFailed
;
188 /* initialize runtime */
189 pthread_once(&initialized
, __SCNetworkConnectionInitialize
);
191 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("__SCNetworkConnectionCreatePrivate:"));
193 /* allocate NetworkConnection */
194 size
= sizeof(SCNetworkConnectionPrivate
) - sizeof(CFRuntimeBase
);
195 connectionPrivate
= (SCNetworkConnectionPrivateRef
)_CFRuntimeCreateInstance(allocator
, __kSCNetworkConnectionTypeID
,size
, NULL
);
196 if (connectionPrivate
== 0)
199 /* zero the data structure */
200 bzero(((u_char
*)connectionPrivate
)+sizeof(CFRuntimeBase
), size
);
202 /* save the serviceID */
203 connectionPrivate
->serviceID
= CFStringCreateCopy(NULL
, serviceID
);
205 connectionPrivate
->controlRef
= -1;
206 connectionPrivate
->eventRef
= -1;
208 if (PPPInit(&connectionPrivate
->controlRef
))
211 if (PPPStatus(connectionPrivate
->controlRef
, serviceID
, 0, &stats
)) {
212 error
= kSCStatusInvalidArgument
; // XXX can't get status, invalid service id
216 CFAllocatorDeallocate(NULL
, stats
);
219 /* success, return the connection reference */
220 return connectionPrivate
;
224 /* failure, clean up and leave */
225 if (connectionPrivate
)
226 CFRelease(connectionPrivate
);
228 CFAllocatorDeallocate(NULL
, stats
);
233 /* -------------------------------------------------------------------------------------------
234 ------------------------------------------------------------------------------------------- */
237 SCNetworkConnectionGetTypeID (void) {
238 pthread_once(&initialized
, __SCNetworkConnectionInitialize
); /* initialize runtime */
239 return __kSCNetworkConnectionTypeID
;
242 /* -------------------------------------------------------------------------------------------
243 ------------------------------------------------------------------------------------------- */
244 static SCNetworkConnectionStatus
245 __SCNetworkConnectionConvertStatus (int state
)
247 SCNetworkConnectionStatus status
= kSCNetworkConnectionDisconnected
;
251 case PPP_CONNECTLINK
:
253 case PPP_AUTHENTICATE
:
257 status
= kSCNetworkConnectionConnecting
;
260 case PPP_DISCONNECTLINK
:
262 status
= kSCNetworkConnectionDisconnecting
;
266 status
= kSCNetworkConnectionConnected
;
269 case PPP_STATERESERVED
:
271 status
= kSCNetworkConnectionDisconnected
;
276 /* -------------------------------------------------------------------------------------------
277 ------------------------------------------------------------------------------------------- */
279 SCNetworkConnectionRef
280 SCNetworkConnectionCreateWithServiceID (CFAllocatorRef allocator
,
281 CFStringRef serviceID
,
282 SCNetworkConnectionCallBack callout
,
283 SCNetworkConnectionContext
*context
)
285 SCNetworkConnectionPrivateRef connectionPrivate
;
287 if (!isA_CFString(serviceID
)) {
288 _SCErrorSet(kSCStatusInvalidArgument
);
292 connectionPrivate
= __SCNetworkConnectionCreatePrivate(allocator
, serviceID
);
294 if (connectionPrivate
) {
295 connectionPrivate
->rlsFunction
= callout
;
297 bcopy(context
, &connectionPrivate
->rlsContext
, sizeof(SCNetworkConnectionContext
));
298 if (context
->retain
) {
299 connectionPrivate
->rlsContext
.info
= (void *)context
->retain(context
->info
);
304 return (SCNetworkConnectionRef
)connectionPrivate
;
307 /* -------------------------------------------------------------------------------------------
308 ------------------------------------------------------------------------------------------- */
311 SCNetworkConnectionCopyServiceID (SCNetworkConnectionRef connection
)
313 if (!isA_SCNetworkConnection(connection
)) {
314 _SCErrorSet(kSCStatusInvalidArgument
);
318 return CFRetain(((SCNetworkConnectionPrivateRef
)connection
)->serviceID
);
321 /* -------------------------------------------------------------------------------------------
322 ------------------------------------------------------------------------------------------- */
325 SCNetworkConnectionCopyStatistics (SCNetworkConnectionRef connection
)
327 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
328 int error
= kSCStatusFailed
;
329 struct ppp_status
*stats
= 0;
330 CFMutableDictionaryRef dict
= 0;
331 CFMutableDictionaryRef statsdict
= 0;
333 #define ADDNUMBER(d, k, n) \
336 num = CFNumberCreate(NULL, kCFNumberSInt32Type, n); \
338 CFDictionaryAddValue(d, k, num); \
343 if (!isA_SCNetworkConnection(connection
)) {
344 _SCErrorSet(kSCStatusInvalidArgument
);
348 /* get status and check connected state */
349 if (PPPStatus(connectionPrivate
->controlRef
, connectionPrivate
->serviceID
, 0, &stats
))
352 if (__SCNetworkConnectionConvertStatus(stats
->status
) != kSCNetworkConnectionConnected
)
355 /* create dictionaries */
356 if ((statsdict
= CFDictionaryCreateMutable(NULL
, 0, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
)) == 0)
359 if ((dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
)) == 0)
363 ADDNUMBER(dict
, kSCNetworkConnectionBytesIn
, &stats
->s
.run
.inBytes
);
364 ADDNUMBER(dict
, kSCNetworkConnectionBytesOut
, &stats
->s
.run
.outBytes
);
365 ADDNUMBER(dict
, kSCNetworkConnectionPacketsIn
, &stats
->s
.run
.inPackets
);
366 ADDNUMBER(dict
, kSCNetworkConnectionPacketsOut
, &stats
->s
.run
.outPackets
);
367 ADDNUMBER(dict
, kSCNetworkConnectionErrorsIn
, &stats
->s
.run
.inErrors
);
368 ADDNUMBER(dict
, kSCNetworkConnectionErrorsOut
, &stats
->s
.run
.outErrors
);
370 /* add the PPP dictionary to the statistics dictionary */
371 CFDictionaryAddValue(statsdict
, kSCEntNetPPP
, dict
);
375 CFAllocatorDeallocate(NULL
, stats
);
381 CFAllocatorDeallocate(NULL
, stats
);
385 CFRelease(statsdict
);
390 /* -------------------------------------------------------------------------------------------
391 ------------------------------------------------------------------------------------------- */
393 SCNetworkConnectionStatus
394 SCNetworkConnectionGetStatus (SCNetworkConnectionRef connection
)
396 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
397 struct ppp_status
*stats
= 0;
398 SCNetworkConnectionStatus status
;
400 if (!isA_SCNetworkConnection(connection
)) {
401 _SCErrorSet(kSCStatusInvalidArgument
);
405 if (PPPStatus(connectionPrivate
->controlRef
, connectionPrivate
->serviceID
, 0, &stats
))
406 return kSCNetworkConnectionDisconnected
; // XXX
408 status
= __SCNetworkConnectionConvertStatus(stats
->status
);
410 CFAllocatorDeallocate(NULL
, stats
);
414 /* -------------------------------------------------------------------------------------------
415 ------------------------------------------------------------------------------------------- */
417 SCNetworkConnectionCopyExtendedStatus (SCNetworkConnectionRef connection
)
419 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
420 CFPropertyListRef status
= 0;
424 if (!isA_SCNetworkConnection(connection
)) {
425 _SCErrorSet(kSCStatusInvalidArgument
);
429 if (PPPExtendedStatus(connectionPrivate
->controlRef
, connectionPrivate
->serviceID
, 0, &data
, &datalen
))
433 || !(status
= PPPUnserialize(data
, datalen
))
434 || !isA_CFDictionary(status
))
437 CFAllocatorDeallocate(NULL
, data
);
442 _SCErrorSet(kSCStatusFailed
);
446 CFAllocatorDeallocate(NULL
, data
);
450 /* -------------------------------------------------------------------------------------------
451 ------------------------------------------------------------------------------------------- */
454 SCNetworkConnectionStart (SCNetworkConnectionRef connection
,
455 CFDictionaryRef userOptions
,
458 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
459 CFDataRef dataref
= 0;
461 u_int32_t datalen
= 0;
463 if (!isA_SCNetworkConnection(connection
)) {
464 _SCErrorSet(kSCStatusInvalidArgument
);
468 if (userOptions
&& !(dataref
= PPPSerialize(userOptions
, &data
, &datalen
)))
471 if (PPPConnect(connectionPrivate
->controlRef
, connectionPrivate
->serviceID
, 0, data
, datalen
, linger
))
477 /* connection is now started */
484 _SCErrorSet(kSCStatusFailed
); // XXX
488 /* -------------------------------------------------------------------------------------------
489 ------------------------------------------------------------------------------------------- */
492 SCNetworkConnectionStop (SCNetworkConnectionRef connection
,
493 Boolean forceDisconnect
)
495 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
497 if (!isA_SCNetworkConnection(connection
)) {
498 _SCErrorSet(kSCStatusInvalidArgument
);
502 if (PPPDisconnect(connectionPrivate
->controlRef
, connectionPrivate
->serviceID
, 0, forceDisconnect
)) {
503 _SCErrorSet(kSCStatusFailed
);
507 /* connection is now disconnecting */
511 /* -------------------------------------------------------------------------------------------
512 ------------------------------------------------------------------------------------------- */
515 SCNetworkConnectionSuspend (SCNetworkConnectionRef connection
)
517 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
519 if (!isA_SCNetworkConnection(connection
)) {
520 _SCErrorSet(kSCStatusInvalidArgument
);
524 if (PPPSuspend(connectionPrivate
->controlRef
, connectionPrivate
->serviceID
, 0)) {
525 _SCErrorSet(kSCStatusFailed
);
529 /* connection is now suspended */
533 /* -------------------------------------------------------------------------------------------
534 ------------------------------------------------------------------------------------------- */
537 SCNetworkConnectionResume (SCNetworkConnectionRef connection
)
539 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
541 if (!isA_SCNetworkConnection(connection
)) {
542 _SCErrorSet(kSCStatusInvalidArgument
);
546 if (PPPResume(connectionPrivate
->controlRef
, connectionPrivate
->serviceID
, 0)) {
547 _SCErrorSet(kSCStatusFailed
);
551 /* connection is now resume */
555 /* -------------------------------------------------------------------------------------------
556 ------------------------------------------------------------------------------------------- */
559 SCNetworkConnectionCopyUserOptions (SCNetworkConnectionRef connection
)
561 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
564 CFPropertyListRef userOptions
= 0;
566 if (!isA_SCNetworkConnection(connection
)) {
567 _SCErrorSet(kSCStatusInvalidArgument
);
571 if (PPPGetConnectData(connectionPrivate
->controlRef
, connectionPrivate
->serviceID
, 0, &data
, &datalen
))
574 // no data were used, return an empty dictionary
576 CFDictionaryRef dict
;
578 dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
580 _SCErrorSet(kSCStatusFailed
); // XXX
584 userOptions
= PPPUnserialize(data
, datalen
);
585 if (!isA_CFDictionary(userOptions
))
588 CFAllocatorDeallocate(NULL
, data
);
593 _SCErrorSet(kSCStatusFailed
);
595 CFRelease(userOptions
);
597 CFAllocatorDeallocate(NULL
, data
);
601 /* -------------------------------------------------------------------------------------------
602 ------------------------------------------------------------------------------------------- */
605 __isScheduled(CFTypeRef obj
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
, CFMutableArrayRef rlList
)
608 CFIndex n
= CFArrayGetCount(rlList
);
610 for (i
= 0; i
< n
; i
+= 3) {
611 if (obj
&& !CFEqual(obj
, CFArrayGetValueAtIndex(rlList
, i
))) {
614 if (runLoop
&& !CFEqual(runLoop
, CFArrayGetValueAtIndex(rlList
, i
+1))) {
617 if (runLoopMode
&& !CFEqual(runLoopMode
, CFArrayGetValueAtIndex(rlList
, i
+2))) {
626 /* -------------------------------------------------------------------------------------------
627 ------------------------------------------------------------------------------------------- */
629 __schedule(CFTypeRef obj
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
, CFMutableArrayRef rlList
)
631 CFArrayAppendValue(rlList
, obj
);
632 CFArrayAppendValue(rlList
, runLoop
);
633 CFArrayAppendValue(rlList
, runLoopMode
);
638 /* -------------------------------------------------------------------------------------------
639 ------------------------------------------------------------------------------------------- */
641 __unschedule(CFTypeRef obj
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
, CFMutableArrayRef rlList
, Boolean all
)
644 Boolean found
= FALSE
;
645 CFIndex n
= CFArrayGetCount(rlList
);
648 if (obj
&& !CFEqual(obj
, CFArrayGetValueAtIndex(rlList
, i
))) {
652 if (runLoop
&& !CFEqual(runLoop
, CFArrayGetValueAtIndex(rlList
, i
+1))) {
656 if (runLoopMode
&& !CFEqual(runLoopMode
, CFArrayGetValueAtIndex(rlList
, i
+2))) {
663 CFArrayRemoveValueAtIndex(rlList
, i
+ 2);
664 CFArrayRemoveValueAtIndex(rlList
, i
+ 1);
665 CFArrayRemoveValueAtIndex(rlList
, i
);
677 /* -------------------------------------------------------------------------------------------
678 ------------------------------------------------------------------------------------------- */
681 __SCNetworkConnectionCallBack(CFSocketRef inref
,
682 CFSocketCallBackType type
,
688 void (*context_release
)(const void *);
689 SCNetworkConnectionRef connection
= (SCNetworkConnectionRef
)info
;
690 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
691 SCNetworkConnectionCallBack rlsFunction
;
692 SCNetworkConnectionStatus status
;
696 err
= PPPReadEvent(connectionPrivate
->eventRef
, &pppstatus
);
700 rlsFunction
= connectionPrivate
->rlsFunction
;
701 if (connectionPrivate
->rlsContext
.retain
&& connectionPrivate
->rlsContext
.info
) {
702 context_info
= (void *)connectionPrivate
->rlsContext
.retain(connectionPrivate
->rlsContext
.info
);
703 context_release
= connectionPrivate
->rlsContext
.release
;
706 context_info
= connectionPrivate
->rlsContext
.info
;
707 context_release
= NULL
;
710 status
= __SCNetworkConnectionConvertStatus(pppstatus
);
712 (*rlsFunction
)(connection
, status
, context_info
);
713 if (context_release
&& context_info
) {
714 context_release(context_info
);
718 /* -------------------------------------------------------------------------------------------
719 ------------------------------------------------------------------------------------------- */
722 SCNetworkConnectionScheduleWithRunLoop(SCNetworkConnectionRef connection
,
723 CFRunLoopRef runLoop
,
724 CFStringRef runLoopMode
)
726 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
729 if (!isA_SCNetworkConnection(connection
) || runLoop
== NULL
|| runLoopMode
== NULL
) {
730 _SCErrorSet(kSCStatusInvalidArgument
);
734 if (connectionPrivate
->rlsFunction
== 0) {
735 _SCErrorSet(kSCStatusInvalidArgument
);
739 if (connectionPrivate
->rlList
740 && __isScheduled(NULL
, runLoop
, runLoopMode
, connectionPrivate
->rlList
)) {
741 /* already scheduled */
742 _SCErrorSet(kSCStatusFailed
);
746 if (connectionPrivate
->eventRef
== -1) {
747 CFSocketContext context
= { 0, (void*)connection
, CFRetain
, CFRelease
, CFCopyDescription
};
749 if (PPPInit(&connectionPrivate
->eventRef
)) {
750 _SCErrorSet(kSCStatusFailed
);
754 PPPEnableEvents(connectionPrivate
->eventRef
, connectionPrivate
->serviceID
, 0, 1);
756 connectionPrivate
->eventRefCF
= CFSocketCreateWithNative(NULL
, connectionPrivate
->eventRef
,
757 kCFSocketReadCallBack
, __SCNetworkConnectionCallBack
, &context
);
758 connectionPrivate
->rls
= CFSocketCreateRunLoopSource(NULL
, connectionPrivate
->eventRefCF
, 0);
759 connectionPrivate
->rlList
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
764 CFRunLoopAddSource(runLoop
, connectionPrivate
->rls
, runLoopMode
);
765 __schedule(connectionPrivate
, runLoop
, runLoopMode
, connectionPrivate
->rlList
);
770 /* -------------------------------------------------------------------------------------------
771 ------------------------------------------------------------------------------------------- */
774 SCNetworkConnectionUnscheduleFromRunLoop(SCNetworkConnectionRef connection
,
775 CFRunLoopRef runLoop
,
776 CFStringRef runLoopMode
)
778 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
780 if (!isA_SCNetworkConnection(connection
) || runLoop
== NULL
|| runLoopMode
== NULL
) {
781 _SCErrorSet(kSCStatusInvalidArgument
);
785 if (connectionPrivate
->rlList
== NULL
786 || !__unschedule(connectionPrivate
, runLoop
, runLoopMode
, connectionPrivate
->rlList
, FALSE
)) {
787 /* if not currently scheduled */
788 _SCErrorSet(kSCStatusFailed
);
792 CFRunLoopRemoveSource(runLoop
, connectionPrivate
->rls
, runLoopMode
);
794 if (CFArrayGetCount(connectionPrivate
->rlList
) == 0) {
795 CFRelease(connectionPrivate
->rls
);
796 connectionPrivate
->rls
= NULL
;
797 CFRelease(connectionPrivate
->rlList
);
798 connectionPrivate
->rlList
= NULL
;
799 //PPPDispose(connectionPrivate->eventRef);
800 CFSocketInvalidate(connectionPrivate
->eventRefCF
);
801 CFRelease(connectionPrivate
->eventRefCF
);
802 connectionPrivate
->eventRefCF
= 0;
803 connectionPrivate
->eventRef
= -1;
810 //************************* USER LEVEL DIAL API **********************************
813 #define k_NetworkConnect_Pref_File CFSTR("com.apple.networkConnect")
814 #define k_InterentConnect_Pref_File CFSTR("com.apple.internetconnect")
816 #define k_Dial_Default_Key CFSTR("ConnectByDefault") // needs to go into SC
817 #define k_Last_Service_Id_Key CFSTR("ServiceID")
818 #define k_Unique_Id_Key CFSTR("UniqueIdentifier")
821 /* Private Prototypes */
822 static Boolean
SCNetworkConnectionPrivateCopyDefaultServiceIDForDial (SCDynamicStoreRef session
, CFStringRef
*serviceID
);
823 static Boolean
SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore (SCDynamicStoreRef session
, CFStringRef
*serviceID
);
824 static Boolean
SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray(CFArrayRef userOptionsArray
, CFDictionaryRef
*userOptions
);
825 static Boolean
SCNetworkConnectionPrivateIsPPPService (SCDynamicStoreRef session
, CFStringRef serviceID
);
826 static void addPasswordFromKeychain(CFDictionaryRef
*userOptions
);
827 static CFArrayRef
copyKeychainEnumerator(CFStringRef uniqueIdentifier
);
830 SCNetworkConnectionCopyUserPreferences (CFDictionaryRef selectionOptions
,
831 CFStringRef
*serviceID
,
832 CFDictionaryRef
*userOptions
)
834 SCDynamicStoreRef session
= SCDynamicStoreCreate(NULL
, CFSTR("SCNetworkConnection"), NULL
, NULL
);
835 Boolean success
= FALSE
;
837 // NOTE: we are currently ignoring selectionOptions
839 if (session
!= NULL
) {
840 // (1) Figure out which service ID we care about, allocate it into passed "serviceID"
841 success
= SCNetworkConnectionPrivateCopyDefaultServiceIDForDial(session
, serviceID
);
843 if (success
&& (*serviceID
!= NULL
)) {
844 // (2) Get the list of user data for this service ID
845 CFPropertyListRef userServices
= CFPreferencesCopyValue(*serviceID
,
846 k_NetworkConnect_Pref_File
,
847 kCFPreferencesCurrentUser
,
848 kCFPreferencesCurrentHost
);
850 // (3) We are expecting an array if the user has defined records for this service ID or NULL if the user hasn't
851 if (userServices
!= NULL
) {
852 if (isA_CFArray(userServices
)) {
853 // (4) Get the default set of user options for this service
854 success
= SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray(
855 (CFArrayRef
)userServices
,
857 if(success
&& userOptions
!= NULL
)
859 addPasswordFromKeychain(userOptions
);
862 fprintf(stderr
, "Error, userServices are not of type CFArray!\n");
865 CFRelease(userServices
); // this is OK because SCNetworkConnectionPrivateISExpectedCFType() checks for NULL
871 fprintf(stderr
, "Error, SCNetworkConnectionCopyUserPreferences, SCDynamicStoreCreate() returned NULL!\n");
877 //*******************************************************************************************
878 // SCNetworkConnectionPrivateCopyDefaultServiceIDForDial
879 // ----------------------------------------------------
880 // Try to find the service id to connect
881 // (1) Start by looking at the last service used in Internet Connect
882 // (2) If Internet Connect has not been used, find the PPP service with the highest ordering
883 //********************************************************************************************
885 SCNetworkConnectionPrivateCopyDefaultServiceIDForDial(SCDynamicStoreRef session
, CFStringRef
*serviceID
)
887 Boolean foundService
= FALSE
;
888 CFPropertyListRef lastServiceSelectedInIC
= NULL
;
890 // NULL out the pointer
893 // read out the last service from the Internet Connect preference file
894 lastServiceSelectedInIC
= CFPreferencesCopyValue(k_Last_Service_Id_Key
,
895 k_InterentConnect_Pref_File
,
896 kCFPreferencesCurrentUser
,
897 kCFPreferencesAnyHost
);
899 // we found the service the user last had open in IC
900 if (lastServiceSelectedInIC
!= NULL
) {
901 // make sure its a PPP service
902 if (SCNetworkConnectionPrivateIsPPPService(session
, lastServiceSelectedInIC
)) {
903 // make sure the service that we found is valid
904 CFDictionaryRef dict
;
907 key
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
908 kSCDynamicStoreDomainSetup
,
909 lastServiceSelectedInIC
,
911 dict
= SCDynamicStoreCopyValue(session
, key
);
914 *serviceID
= CFRetain(lastServiceSelectedInIC
);
919 CFRelease(lastServiceSelectedInIC
);
923 foundService
= SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore(session
, serviceID
);
929 //********************************************************************************
930 // SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore
931 // -------------------------------------------------------
932 // Find the highest ordered PPP service in the dynamic store
933 //********************************************************************************
935 SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore(SCDynamicStoreRef session
, CFStringRef
*serviceID
)
937 Boolean success
= FALSE
;
938 CFStringRef key
= NULL
;
939 CFDictionaryRef dict
= NULL
;
940 CFArrayRef serviceIDs
= NULL
;
948 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainSetup
, kSCEntNetIPv4
);
950 fprintf(stderr
, "Error, Setup Key == NULL!\n");
954 dict
= SCDynamicStoreCopyValue(session
, key
);
956 fprintf(stderr
, "Error, Dictionary for setup key == NULL!\n");
960 serviceIDs
= CFDictionaryGetValue(dict
, kSCPropNetServiceOrder
); // array of service id's
961 if (isA_CFArray(serviceIDs
) == NULL
) {
962 if (serviceIDs
== NULL
)
963 fprintf(stderr
, "Error, Array of service IDs == NULL!\n");
965 fprintf(stderr
, "Error, serviceIds are not of type CFArray!\n");
969 count
= CFArrayGetCount(serviceIDs
);
970 for (i
= 0; i
< count
; i
++) {
971 CFStringRef service
= CFArrayGetValueAtIndex(serviceIDs
, i
);
973 if (SCNetworkConnectionPrivateIsPPPService(session
, service
)) {
974 *serviceID
= CFRetain(service
);
990 //********************************************************************************
991 // SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray
992 // ---------------------------------------------------------
993 // Copy over user preferences for a particular service if they exist
994 //********************************************************************************
996 SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray(CFArrayRef userOptionsArray
, CFDictionaryRef
*userOptions
)
998 CFIndex count
= CFArrayGetCount(userOptionsArray
);
1001 *userOptions
= NULL
;
1003 for (i
= 0; i
< count
; i
++) {
1004 // (1) Find the dictionary
1005 CFPropertyListRef propertyList
= CFArrayGetValueAtIndex(userOptionsArray
, i
);
1007 if (isA_CFDictionary(propertyList
) != NULL
) {
1008 // See if there's a value for dial on demand
1009 CFPropertyListRef value
= CFDictionaryGetValue((CFDictionaryRef
)propertyList
,
1010 k_Dial_Default_Key
);
1011 if (isA_CFBoolean(value
) != NULL
) {
1012 if (CFBooleanGetValue(value
)) {
1013 // we found the default user options
1014 *userOptions
= CFDictionaryCreateCopy(NULL
,
1015 (CFDictionaryRef
)propertyList
);
1025 //********************************************************************************
1026 // SCNetworkConnectionPrivateIsPPPService
1027 // --------------------------------------
1028 // Check and see if the service is a PPP service
1029 //********************************************************************************
1031 SCNetworkConnectionPrivateIsPPPService(SCDynamicStoreRef session
, CFStringRef serviceID
)
1033 CFStringRef entityKey
;
1034 Boolean isPPPService
= FALSE
;
1035 Boolean isModemOrPPPoE
= FALSE
;
1037 entityKey
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1038 kSCDynamicStoreDomainSetup
,
1040 kSCEntNetInterface
);
1041 if (entityKey
!= NULL
) {
1042 CFDictionaryRef serviceDict
;
1044 serviceDict
= SCDynamicStoreCopyValue(session
, entityKey
);
1045 if (serviceDict
!= NULL
) {
1046 if (isA_CFDictionary(serviceDict
)) {
1048 CFStringRef subtype
;
1050 type
= CFDictionaryGetValue(serviceDict
, kSCPropNetInterfaceType
);
1051 if (isA_CFString(type
)) {
1052 isPPPService
= CFEqual(type
, kSCValNetInterfaceTypePPP
);
1055 subtype
= CFDictionaryGetValue(serviceDict
, kSCPropNetInterfaceSubType
);
1056 if (isA_CFString(subtype
)) {
1057 isModemOrPPPoE
= (CFEqual(subtype
, kSCValNetInterfaceSubTypePPPSerial
) ||
1058 CFEqual(subtype
, kSCValNetInterfaceSubTypePPPoE
));
1061 CFRelease(serviceDict
);
1063 CFRelease(entityKey
);
1066 return (isPPPService
&& isModemOrPPPoE
);
1069 //********************************************************************************
1070 // addPasswordFromKeychain
1071 // --------------------------------------
1072 // Get the password out of the keychain and add it to the PPP dictionary
1073 //********************************************************************************
1075 addPasswordFromKeychain(CFDictionaryRef
*userOptions
)
1077 CFArrayRef enumerator
;
1079 CFDictionaryRef oldDict
;
1080 CFPropertyListRef uniqueID
= NULL
;
1082 oldDict
= *userOptions
;
1083 if(oldDict
== NULL
) {
1084 return; // if no userOptions
1087 uniqueID
= CFDictionaryGetValue(oldDict
, k_Unique_Id_Key
);
1088 if(!isA_CFString(uniqueID
)) {
1089 return; // if no unique ID
1092 enumerator
= copyKeychainEnumerator(uniqueID
);
1093 if(enumerator
== NULL
) {
1094 return; // if no keychain enumerator
1098 n
= CFArrayGetCount(enumerator
);
1102 SecKeychainItemRef itemRef
;
1105 itemRef
= (SecKeychainItemRef
)CFArrayGetValueAtIndex(enumerator
, 0);
1106 result
= SecKeychainItemCopyContent(itemRef
, // itemRef
1110 (void *)&data
); // outData
1111 if(result
== noErr
&& data
!= NULL
&& dataLen
> 0) {
1114 pass
= CFStringCreateWithBytes(NULL
, data
, dataLen
, kCFStringEncodingUTF8
, TRUE
);
1116 CFMutableDictionaryRef newDict
;
1117 CFMutableDictionaryRef newPPP
;
1118 CFDictionaryRef pppDict
;
1120 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, oldDict
);
1121 pppDict
= CFDictionaryGetValue(newDict
, kSCEntNetPPP
);
1122 if (isA_CFDictionary(pppDict
)) {
1123 newPPP
= CFDictionaryCreateMutableCopy(NULL
, 0, pppDict
);
1125 newPPP
= CFDictionaryCreateMutable(NULL
,
1127 &kCFTypeDictionaryKeyCallBacks
,
1128 &kCFTypeDictionaryValueCallBacks
);
1131 // set the PPP password
1132 CFDictionarySetValue(newPPP
, kSCPropNetPPPAuthPassword
, pass
);
1135 // update the PPP entity
1136 CFDictionarySetValue(newDict
, kSCEntNetPPP
, newPPP
);
1139 // update the userOptions dictionary
1141 *userOptions
= CFDictionaryCreateCopy(NULL
, newDict
);
1147 CFRelease(enumerator
);
1151 //********************************************************************************
1152 // copyKeychainEnumerator
1153 // --------------------------------------
1154 // Gather Keychain Enumerator
1155 //********************************************************************************
1157 copyKeychainEnumerator(CFStringRef uniqueIdentifier
)
1160 CFMutableArrayRef itemArray
= NULL
;
1162 SecKeychainSearchRef search
= NULL
;
1164 buf
= _SC_cfstring_to_cstring(uniqueIdentifier
, NULL
, 0, kCFStringEncodingUTF8
);
1166 // search for unique identifier in "svce" attribute
1167 SecKeychainAttribute attributes
[] = {{ kSecServiceItemAttr
,
1168 CFStringGetLength(uniqueIdentifier
),
1172 SecKeychainAttributeList attrList
= { sizeof(attributes
) / sizeof(*attributes
),
1175 result
= SecKeychainSearchCreateFromAttributes(NULL
, kSecGenericPasswordItemClass
, &attrList
, &search
);
1176 if (result
== noErr
) {
1177 itemArray
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1179 while (result
== noErr
) {
1180 SecKeychainItemRef itemFound
= NULL
;
1182 result
= SecKeychainSearchCopyNext(search
, &itemFound
);
1183 if (result
!= noErr
) {
1188 CFArrayAppendValue(itemArray
, itemFound
);
1189 CFRelease(itemFound
);
1195 if (search
) CFRelease(search
);
1196 if (buf
) CFAllocatorDeallocate(NULL
, buf
);