2 * Copyright (c) 2012 Apple 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 Copyright (c) 2000-2012, Apple Inc. All rights reserved.
26 Responsibility: Jeremy Wyld
28 // Original Author: Becky Willrich
29 #include <CoreFoundation/CFStream.h>
30 #include <CoreFoundation/CFNumber.h>
31 #include "CFInternal.h"
32 #include "CFStreamInternal.h"
33 #include "CFStreamPriv.h"
35 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
36 // On Mach these live in CF for historical reasons, even though they are declared in CFNetwork
38 const int kCFStreamErrorDomainSSL
= 3;
39 const int kCFStreamErrorDomainSOCKS
= 5;
41 CONST_STRING_DECL(kCFStreamPropertyShouldCloseNativeSocket
, "kCFStreamPropertyShouldCloseNativeSocket")
42 CONST_STRING_DECL(kCFStreamPropertyAutoErrorOnSystemChange
, "kCFStreamPropertyAutoErrorOnSystemChange");
44 CONST_STRING_DECL(kCFStreamPropertySOCKSProxy
, "kCFStreamPropertySOCKSProxy")
45 CONST_STRING_DECL(kCFStreamPropertySOCKSProxyHost
, "SOCKSProxy")
46 CONST_STRING_DECL(kCFStreamPropertySOCKSProxyPort
, "SOCKSPort")
47 CONST_STRING_DECL(kCFStreamPropertySOCKSVersion
, "kCFStreamPropertySOCKSVersion")
48 CONST_STRING_DECL(kCFStreamSocketSOCKSVersion4
, "kCFStreamSocketSOCKSVersion4")
49 CONST_STRING_DECL(kCFStreamSocketSOCKSVersion5
, "kCFStreamSocketSOCKSVersion5")
50 CONST_STRING_DECL(kCFStreamPropertySOCKSUser
, "kCFStreamPropertySOCKSUser")
51 CONST_STRING_DECL(kCFStreamPropertySOCKSPassword
, "kCFStreamPropertySOCKSPassword")
53 CONST_STRING_DECL(kCFStreamPropertySocketSecurityLevel
, "kCFStreamPropertySocketSecurityLevel");
54 CONST_STRING_DECL(kCFStreamSocketSecurityLevelNone
, "kCFStreamSocketSecurityLevelNone");
55 CONST_STRING_DECL(kCFStreamSocketSecurityLevelSSLv2
, "kCFStreamSocketSecurityLevelSSLv2");
56 CONST_STRING_DECL(kCFStreamSocketSecurityLevelSSLv3
, "kCFStreamSocketSecurityLevelSSLv3");
57 CONST_STRING_DECL(kCFStreamSocketSecurityLevelTLSv1
, "kCFStreamSocketSecurityLevelTLSv1");
58 CONST_STRING_DECL(kCFStreamSocketSecurityLevelNegotiatedSSL
, "kCFStreamSocketSecurityLevelNegotiatedSSL");
63 #if DEPLOYMENT_TARGET_WINDOWS
64 typedef void (*CF_SOCKET_STREAM_PAIR
)(CFAllocatorRef
, CFStringRef
, UInt32
, CFSocketNativeHandle
, const CFSocketSignature
*, CFReadStreamRef
*, CFWriteStreamRef
*);
67 // These are duplicated in CFNetwork, who actually externs them in its headers
68 CONST_STRING_DECL(kCFStreamPropertySocketSSLContext
, "kCFStreamPropertySocketSSLContext")
69 CONST_STRING_DECL(_kCFStreamPropertySocketSecurityAuthenticatesServerCertificate
, "_kCFStreamPropertySocketSecurityAuthenticatesServerCertificate");
73 void _CFSocketStreamSetAuthenticatesServerCertificateDefault(Boolean shouldAuthenticate
) {
74 CFLog(__kCFLogAssertion
, CFSTR("_CFSocketStreamSetAuthenticatesServerCertificateDefault(): This call has been deprecated. Use SetProperty(_kCFStreamPropertySocketSecurityAuthenticatesServerCertificate, kCFBooleanTrue/False)\n"));
78 /* CF_EXPORT */ Boolean
79 _CFSocketStreamGetAuthenticatesServerCertificateDefault(void) {
80 CFLog(__kCFLogAssertion
, CFSTR("_CFSocketStreamGetAuthenticatesServerCertificateDefault(): This call has been removed as a security risk. Use security properties on individual streams instead.\n"));
86 _CFSocketStreamPairSetAuthenticatesServerCertificate(CFReadStreamRef rStream
, CFWriteStreamRef wStream
, Boolean authenticates
) {
88 CFBooleanRef value
= (!authenticates
? kCFBooleanFalse
: kCFBooleanTrue
);
91 CFReadStreamSetProperty(rStream
, _kCFStreamPropertySocketSecurityAuthenticatesServerCertificate
, value
);
93 CFWriteStreamSetProperty(wStream
, _kCFStreamPropertySocketSecurityAuthenticatesServerCertificate
, value
);
97 // Flags for dyld loading of libraries.
106 #if DEPLOYMENT_TARGET_WINDOWS
109 void (*_CFSocketStreamCreatePair
)(CFAllocatorRef
, CFStringRef
, UInt32
, CFSocketNativeHandle
, const CFSocketSignature
*, CFReadStreamRef
*, CFWriteStreamRef
*);
110 CFErrorRef (*_CFErrorCreateWithStreamError
)(CFAllocatorRef
, CFStreamError
*);
111 CFStreamError (*_CFStreamErrorFromCFError
)(CFErrorRef
);
112 } CFNetworkSupport
= {
115 #if DEPLOYMENT_TARGET_WINDOWS
123 #define CFNETWORK_CALL(sym, args) ((CFNetworkSupport.sym)args)
125 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
126 #define CFNETWORK_LOAD_SYM(sym) __CFLookupCFNetworkFunction(#sym)
127 #elif DEPLOYMENT_TARGET_WINDOWS
128 #define CFNETWORK_LOAD_SYM(sym) (void *)GetProcAddress(CFNetworkSupport.image, #sym)
131 static void initializeCFNetworkSupport(void) {
132 __CFBitSet(CFNetworkSupport
.flags
, kTriedToLoad
);
134 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
135 CFNetworkSupport
._CFSocketStreamCreatePair
= CFNETWORK_LOAD_SYM(_CFSocketStreamCreatePair
);
136 CFNetworkSupport
._CFErrorCreateWithStreamError
= CFNETWORK_LOAD_SYM(_CFErrorCreateWithStreamError
);
137 CFNetworkSupport
._CFStreamErrorFromCFError
= CFNETWORK_LOAD_SYM(_CFStreamErrorFromCFError
);
138 #elif DEPLOYMENT_TARGET_WINDOWS
139 if (!CFNetworkSupport
.image
) {
141 CFNetworkSupport
.image
= GetModuleHandleW(L
"CFNetwork_debug.dll");
143 CFNetworkSupport
.image
= GetModuleHandleW(L
"CFNetwork.dll");
147 if (!CFNetworkSupport
.image
) {
148 // not loaded yet, try to load from the filesystem
149 char path
[MAX_PATH
+1];
150 if (!CFNetworkSupport
.image
) {
151 strlcpy(path
, (const char *)_CFDLLPath(), sizeof(path
));
153 strlcat(path
, "\\CFNetwork_debug.dll", sizeof(path
));
155 strlcat(path
, "\\CFNetwork.dll", sizeof(path
));
157 CFNetworkSupport
.image
= LoadLibraryA(path
);
161 if (!CFNetworkSupport
.image
) {
162 CFLog(__kCFLogAssertion
, CFSTR("CoreFoundation: failed to dynamically load CFNetwork"));
164 CFNetworkSupport
._CFSocketStreamCreatePair
= (CF_SOCKET_STREAM_PAIR
)CFNETWORK_LOAD_SYM(_CFSocketStreamCreatePair
);
165 CFNetworkSupport
._CFErrorCreateWithStreamError
= (CFErrorRef(*)(CFAllocatorRef
, CFStreamError
*))CFNETWORK_LOAD_SYM(_CFErrorCreateWithStreamError
);
166 CFNetworkSupport
._CFStreamErrorFromCFError
= (CFStreamError(*)(CFErrorRef
))CFNETWORK_LOAD_SYM(_CFStreamErrorFromCFError
);
170 if (!CFNetworkSupport
._CFSocketStreamCreatePair
) CFLog(__kCFLogAssertion
, CFSTR("CoreFoundation: failed to dynamically link symbol _CFSocketStreamCreatePair"));
171 if (!CFNetworkSupport
._CFErrorCreateWithStreamError
) CFLog(__kCFLogAssertion
, CFSTR("CoreFoundation: failed to dynamically link symbol _CFErrorCreateWithStreamError"));
172 if (!CFNetworkSupport
._CFStreamErrorFromCFError
) CFLog(__kCFLogAssertion
, CFSTR("CoreFoundation: failed to dynamically link symbol _CFStreamErrorFromCFError"));
174 __CFBitSet(CFNetworkSupport
.flags
, kInitialized
);
178 createPair(CFAllocatorRef alloc
, CFStringRef host
, UInt32 port
, CFSocketNativeHandle sock
, const CFSocketSignature
* sig
, CFReadStreamRef
*readStream
, CFWriteStreamRef
*writeStream
)
186 __CFSpinLock(&(CFNetworkSupport
.lock
));
187 if (!__CFBitIsSet(CFNetworkSupport
.flags
, kTriedToLoad
)) initializeCFNetworkSupport();
188 __CFSpinUnlock(&(CFNetworkSupport
.lock
));
190 CFNETWORK_CALL(_CFSocketStreamCreatePair
, (alloc
, host
, port
, sock
, sig
, readStream
, writeStream
));
194 CF_EXPORT
void CFStreamCreatePairWithSocket(CFAllocatorRef alloc
, CFSocketNativeHandle sock
, CFReadStreamRef
*readStream
, CFWriteStreamRef
*writeStream
) {
195 createPair(alloc
, NULL
, 0, sock
, NULL
, readStream
, writeStream
);
198 CF_EXPORT
void CFStreamCreatePairWithSocketToHost(CFAllocatorRef alloc
, CFStringRef host
, UInt32 port
, CFReadStreamRef
*readStream
, CFWriteStreamRef
*writeStream
) {
199 createPair(alloc
, host
, port
, 0, NULL
, readStream
, writeStream
);
202 CF_EXPORT
void CFStreamCreatePairWithPeerSocketSignature(CFAllocatorRef alloc
, const CFSocketSignature
* sig
, CFReadStreamRef
*readStream
, CFWriteStreamRef
*writeStream
) {
203 createPair(alloc
, NULL
, 0, 0, sig
, readStream
, writeStream
);
206 __private_extern__ CFStreamError
_CFStreamErrorFromError(CFErrorRef error
) {
207 CFStreamError result
;
210 __CFSpinLock(&(CFNetworkSupport
.lock
));
211 if (!__CFBitIsSet(CFNetworkSupport
.flags
, kTriedToLoad
)) initializeCFNetworkSupport();
212 canUpCall
= (CFNetworkSupport
._CFStreamErrorFromCFError
!= NULL
);
213 __CFSpinUnlock(&(CFNetworkSupport
.lock
));
216 result
= CFNETWORK_CALL(_CFStreamErrorFromCFError
, (error
));
218 CFStringRef domain
= CFErrorGetDomain(error
);
219 if (CFEqual(domain
, kCFErrorDomainPOSIX
)) {
220 result
.domain
= kCFStreamErrorDomainPOSIX
;
221 } else if (CFEqual(domain
, kCFErrorDomainOSStatus
)) {
222 result
.domain
= kCFStreamErrorDomainMacOSStatus
;
223 } else if (CFEqual(domain
, kCFErrorDomainMach
)) {
224 result
.domain
= 11; // kCFStreamErrorDomainMach, but that symbol is in CFNetwork
226 result
.domain
= kCFStreamErrorDomainCustom
;
228 result
.error
= CFErrorGetCode(error
);
233 __private_extern__ CFErrorRef
_CFErrorFromStreamError(CFAllocatorRef alloc
, CFStreamError
*streamError
) {
237 __CFSpinLock(&(CFNetworkSupport
.lock
));
238 if (!__CFBitIsSet(CFNetworkSupport
.flags
, kTriedToLoad
)) initializeCFNetworkSupport();
239 canUpCall
= (CFNetworkSupport
._CFErrorCreateWithStreamError
!= NULL
);
240 __CFSpinUnlock(&(CFNetworkSupport
.lock
));
243 result
= CFNETWORK_CALL(_CFErrorCreateWithStreamError
, (alloc
, streamError
));
245 if (streamError
->domain
== kCFStreamErrorDomainPOSIX
) {
246 return CFErrorCreate(alloc
, kCFErrorDomainPOSIX
, streamError
->error
, NULL
);
247 } else if (streamError
->domain
== kCFStreamErrorDomainMacOSStatus
) {
248 return CFErrorCreate(alloc
, kCFErrorDomainOSStatus
, streamError
->error
, NULL
);
250 CFStringRef key
= CFSTR("CFStreamErrorDomainKey");
251 CFNumberRef value
= CFNumberCreate(alloc
, kCFNumberCFIndexType
, &streamError
->domain
);
252 CFDictionaryRef dict
= CFDictionaryCreate(alloc
, (const void **)(&key
), (const void **)(&value
), 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
253 result
= CFErrorCreate(alloc
, CFSTR("BogusCFStreamErrorCompatibilityDomain"), streamError
->error
, dict
);