2 * Copyright (c) 2005 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@
24 Copyright 1999-2002, Apple, Inc. All rights reserved.
25 Responsibility: Doug Davidson
28 #include <CoreFoundation/CFSocket.h>
29 #include <sys/types.h>
32 #include <CoreFoundation/CFArray.h>
33 #include <CoreFoundation/CFData.h>
34 #include <CoreFoundation/CFDictionary.h>
35 #include <CoreFoundation/CFRunLoop.h>
36 #include <CoreFoundation/CFString.h>
37 #include <CoreFoundation/CFPropertyList.h>
38 #include "CFInternal.h"
39 #if defined(__WIN32__)
42 // Careful with remapping these - different WinSock routines return different errors than
43 // on BSD, so if these are used many places they won't work.
44 #define EINPROGRESS WSAEINPROGRESS
48 #define EBADF WSAENOTSOCK
49 #elif defined(__MACH__)
52 #include <sys/filio.h>
54 #include <sys/socket.h>
55 #include <netinet/in.h>
59 // On Mach we use a v0 RunLoopSource to make client callbacks. That source is signalled by a
60 // separate SocketManager thread who uses select() to watch the sockets' fds.
62 // On Win32 we (primarily) use a v1 RunLoopSource. Code protected by USE_V1_RUN_LOOP_SOURCE currently
63 // assumes __WIN32__ is defined. The Win32 v1 RunLoopSource uses a Windows event object to be notified
64 // of socket events like FD_READ, FD_CONNECT, etc, at which point it can immediately make client
65 // callbacks instead of doing any inter-thread signaling.
67 // Because of the peculiar way that FD_WRITE is signalled (see WSAEventSelect doc in MSDN), we
68 // could not implement the current CFSocket client write callback semantics on top of the FD_WRITE
69 // events received by the v1 source. However, because the performance gains on the read side
70 // were so great with the v1 source, we use a hybrid approach to implement the write side. Read
71 // callbacks are triggered straightforwardly by FD_READ events. Write callbacks are triggered in
72 // two ways. Most commonly, as we return to the core run loop we poll a socket's writability
73 // using select(). If it can accept bytes, we signal our v1 RunLoopSource such that it will be
74 // immediately fired, and we can make the write callback. Alternatively, if the socket is full,
75 // we then use the old v0-style approach of notifying the SocketManager thread to listen for
76 // notification that the socket can accept bytes using select(). Of course these two modes also
77 // must respect the various write callback settings and autoenabling flags setup by the client.
78 // The net effect is that we rarely must interact with the SocketMgr thread, which leads to a
81 // Because of this hybrid, we end up needing both a v1 RunLoopSource (to watch the Windows FD_*
82 // events) and a v0 RunLoopSource (to be signaled from the socket manager). Since our API exports
83 // a single RunLoopSource that clients may schedule, we hand out the v0 RunLoopSource, and as it
84 // is scheduled and canceled we install the v1 RunLoopSource in the same modes.
85 #if defined(__WIN32__)
86 #define USE_V1_RUN_LOOP_SOURCE
89 //#define LOG_CFSOCKET
91 #if !defined(__WIN32__)
92 #define INVALID_SOCKET (CFSocketNativeHandle)(-1)
93 #endif /* __WIN32__ */
95 #define MAX_SOCKADDR_LEN 256
96 #define MAX_DATA_SIZE 32768
98 static uint16_t __CFSocketDefaultNameRegistryPortNumber
= 2454;
100 CONST_STRING_DECL(kCFSocketCommandKey
, "Command")
101 CONST_STRING_DECL(kCFSocketNameKey
, "Name")
102 CONST_STRING_DECL(kCFSocketValueKey
, "Value")
103 CONST_STRING_DECL(kCFSocketResultKey
, "Result")
104 CONST_STRING_DECL(kCFSocketErrorKey
, "Error")
105 CONST_STRING_DECL(kCFSocketRegisterCommand
, "Register")
106 CONST_STRING_DECL(kCFSocketRetrieveCommand
, "Retrieve")
107 CONST_STRING_DECL(__kCFSocketRegistryRequestRunLoopMode
, "CFSocketRegistryRequest")
109 /* locks are to be acquired in the following order:
110 (1) __CFAllSocketsLock
111 (2) an individual CFSocket's lock
112 (3) __CFActiveSocketsLock
114 static CFSpinLock_t __CFAllSocketsLock
= 0; /* controls __CFAllSockets */
115 static CFMutableDictionaryRef __CFAllSockets
= NULL
;
116 static CFSpinLock_t __CFActiveSocketsLock
= 0; /* controls __CFRead/WriteSockets, __CFRead/WriteSocketsFds, __CFSocketManagerThread, and __CFSocketManagerIteration */
117 static volatile UInt32 __CFSocketManagerIteration
= 0;
118 static CFMutableArrayRef __CFWriteSockets
= NULL
;
119 static CFMutableArrayRef __CFReadSockets
= NULL
;
120 static CFMutableDataRef __CFWriteSocketsFds
= NULL
;
121 static CFMutableDataRef __CFReadSocketsFds
= NULL
;
122 #if defined(__WIN32__)
123 // We need to select on exceptFDs on Win32 to hear of connect failures
124 static CFMutableDataRef __CFExceptSocketsFds
= NULL
;
126 static CFDataRef zeroLengthData
= NULL
;
128 static CFSocketNativeHandle __CFWakeupSocketPair
[2] = {INVALID_SOCKET
, INVALID_SOCKET
};
129 static void *__CFSocketManagerThread
= NULL
;
131 #if !defined(__WIN32__)
132 #define CFSOCKET_USE_SOCKETPAIR
133 #define closesocket(a) close((a))
134 #define ioctlsocket(a,b,c) ioctl((a),(b),(c))
137 static CFTypeID __kCFSocketTypeID
= _kCFRuntimeNotATypeID
;
138 static void __CFSocketDoCallback(CFSocketRef s
, CFDataRef data
, CFDataRef address
, CFSocketNativeHandle sock
);
139 static void __CFSocketInvalidate(CFSocketRef s
, Boolean wakeup
);
144 unsigned client
:8; // flags set by client (reenable, CloseOnInvalidate)
145 unsigned disabled
:8; // flags marking disabled callbacks
146 unsigned connected
:1; // Are we connected yet? (also true for connectionless sockets)
147 unsigned writableHint
:1; // Did the polling the socket show it to be writable?
148 unsigned closeSignaled
:1; // Have we seen FD_CLOSE? (only used on Win32)
152 CFSpinLock_t _writeLock
;
153 CFSocketNativeHandle _socket
; /* immutable */
157 CFDataRef _peerAddress
;
158 SInt32 _socketSetCount
;
159 CFRunLoopSourceRef _source0
; // v0 RLS, messaged from SocketMgr
160 CFMutableArrayRef _runLoops
;
161 CFSocketCallBack _callout
; /* immutable */
162 CFSocketContext _context
; /* immutable */
163 #if !defined(USE_V1_RUN_LOOP_SOURCE)
164 CFIndex _maxQueueLen
; // queues to pass data from SocketMgr thread
165 CFMutableArrayRef _dataQueue
;
166 CFMutableArrayRef _addressQueue
;
168 CFRunLoopSourceRef _source1
; // v1 RLS, triggered by _event happenings
169 HANDLE _event
; // used to hear about socket events
170 long _oldEventMask
; // last event mask value set with WSAEventSelect
174 /* Bit 6 in the base reserved bits is used for write-signalled state (mutable) */
175 /* Bit 5 in the base reserved bits is used for read-signalled state (mutable) */
176 /* Bit 4 in the base reserved bits is used for invalid state (mutable) */
177 /* Bits 0-3 in the base reserved bits are used for callback types (immutable) */
178 /* Of this, bits 0-1 are used for the read callback type. */
180 CF_INLINE Boolean
__CFSocketIsWriteSignalled(CFSocketRef s
) {
181 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_info
, 6, 6);
184 CF_INLINE
void __CFSocketSetWriteSignalled(CFSocketRef s
) {
185 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_info
, 6, 6, 1);
188 CF_INLINE
void __CFSocketUnsetWriteSignalled(CFSocketRef s
) {
189 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_info
, 6, 6, 0);
192 CF_INLINE Boolean
__CFSocketIsReadSignalled(CFSocketRef s
) {
193 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_info
, 5, 5);
196 CF_INLINE
void __CFSocketSetReadSignalled(CFSocketRef s
) {
197 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_info
, 5, 5, 1);
200 CF_INLINE
void __CFSocketUnsetReadSignalled(CFSocketRef s
) {
201 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_info
, 5, 5, 0);
204 CF_INLINE Boolean
__CFSocketIsValid(CFSocketRef s
) {
205 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_info
, 4, 4);
208 CF_INLINE
void __CFSocketSetValid(CFSocketRef s
) {
209 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_info
, 4, 4, 1);
212 CF_INLINE
void __CFSocketUnsetValid(CFSocketRef s
) {
213 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_info
, 4, 4, 0);
216 CF_INLINE
uint8_t __CFSocketCallBackTypes(CFSocketRef s
) {
217 return (uint8_t)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_info
, 3, 0);
220 CF_INLINE
uint8_t __CFSocketReadCallBackType(CFSocketRef s
) {
221 return (uint8_t)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_info
, 1, 0);
224 CF_INLINE
void __CFSocketSetCallBackTypes(CFSocketRef s
, uint8_t types
) {
225 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_info
, 3, 0, types
& 0xF);
228 CF_INLINE
void __CFSocketLock(CFSocketRef s
) {
229 __CFSpinLock(&(s
->_lock
));
232 CF_INLINE
void __CFSocketUnlock(CFSocketRef s
) {
233 __CFSpinUnlock(&(s
->_lock
));
236 CF_INLINE
void __CFSocketWriteLock(CFSocketRef s
) {
237 __CFSpinLock(&(s
->_writeLock
));
240 CF_INLINE
void __CFSocketWriteUnlock(CFSocketRef s
) {
241 __CFSpinUnlock(&(s
->_writeLock
));
244 CF_INLINE Boolean
__CFSocketIsConnectionOriented(CFSocketRef s
) {
245 return (SOCK_STREAM
== s
->_socketType
|| SOCK_SEQPACKET
== s
->_socketType
);
248 CF_INLINE Boolean
__CFSocketIsScheduled(CFSocketRef s
) {
249 return (s
->_socketSetCount
> 0);
252 CF_INLINE
void __CFSocketEstablishAddress(CFSocketRef s
) {
253 /* socket should already be locked */
254 uint8_t name
[MAX_SOCKADDR_LEN
];
255 int namelen
= sizeof(name
);
256 if (__CFSocketIsValid(s
) && NULL
== s
->_address
&& INVALID_SOCKET
!= s
->_socket
&& 0 == getsockname(s
->_socket
, (struct sockaddr
*)name
, &namelen
) && NULL
!= name
&& 0 < namelen
) {
257 s
->_address
= CFDataCreate(CFGetAllocator(s
), name
, namelen
);
261 CF_INLINE
void __CFSocketEstablishPeerAddress(CFSocketRef s
) {
262 /* socket should already be locked */
263 uint8_t name
[MAX_SOCKADDR_LEN
];
264 int namelen
= sizeof(name
);
265 if (__CFSocketIsValid(s
) && NULL
== s
->_peerAddress
&& INVALID_SOCKET
!= s
->_socket
&& 0 == getpeername(s
->_socket
, (struct sockaddr
*)name
, &namelen
) && NULL
!= name
&& 0 < namelen
) {
266 s
->_peerAddress
= CFDataCreate(CFGetAllocator(s
), name
, namelen
);
270 CF_INLINE CFIndex
__CFSocketFdGetSize(CFDataRef fdSet
) {
271 #if defined(__WIN32__)
272 fd_set
* set
= (fd_set
*)CFDataGetBytePtr(fdSet
);
273 return set
? set
->fd_count
: 0;
275 return NBBY
* CFDataGetLength(fdSet
);
279 CF_INLINE
int __CFSocketLastError(void) {
280 #if defined(__WIN32__)
281 return WSAGetLastError();
283 return thread_errno();
287 static Boolean
__CFNativeSocketIsValid(CFSocketNativeHandle sock
) {
288 #if defined(__WIN32__)
289 SInt32 errorCode
= 0;
290 int errorSize
= sizeof(errorCode
);
291 return !(0 != getsockopt(sock
, SOL_SOCKET
, SO_ERROR
, (void *)&errorCode
, &errorSize
) && WSAGetLastError() == WSAENOTSOCK
);
293 SInt32 flags
= fcntl(sock
, F_GETFL
, 0);
294 return !(0 > flags
&& EBADF
== thread_errno());
298 CF_INLINE Boolean
__CFSocketFdSet(CFSocketNativeHandle sock
, CFMutableDataRef fdSet
) {
299 /* returns true if a change occurred, false otherwise */
300 Boolean retval
= false;
301 if (INVALID_SOCKET
!= sock
&& 0 <= sock
) {
302 #if defined(__WIN32__)
303 fd_set
* set
= (fd_set
*)CFDataGetMutableBytePtr(fdSet
);
304 if ((set
->fd_count
* sizeof(SOCKET
) + sizeof(u_int
)) >= CFDataGetLength(fdSet
)) {
305 CFDataIncreaseLength(fdSet
, sizeof(SOCKET
));
306 set
= (fd_set
*)CFDataGetMutableBytePtr(fdSet
);
308 if (!FD_ISSET(sock
, set
)) {
313 CFIndex numFds
= NBBY
* CFDataGetLength(fdSet
);
315 if (sock
>= numFds
) {
316 CFIndex oldSize
= numFds
/ NFDBITS
, newSize
= (sock
+ NFDBITS
) / NFDBITS
, changeInBytes
= (newSize
- oldSize
) * sizeof(fd_mask
);
317 CFDataIncreaseLength(fdSet
, changeInBytes
);
318 fds_bits
= (fd_mask
*)CFDataGetMutableBytePtr(fdSet
);
319 memset(fds_bits
+ oldSize
, 0, changeInBytes
);
321 fds_bits
= (fd_mask
*)CFDataGetMutableBytePtr(fdSet
);
323 if (!FD_ISSET(sock
, (fd_set
*)fds_bits
)) {
325 FD_SET(sock
, (fd_set
*)fds_bits
);
332 CF_INLINE Boolean
__CFSocketFdClr(CFSocketNativeHandle sock
, CFMutableDataRef fdSet
) {
333 /* returns true if a change occurred, false otherwise */
334 Boolean retval
= false;
335 if (INVALID_SOCKET
!= sock
&& 0 <= sock
) {
336 #if defined(__WIN32__)
337 fd_set
* set
= (fd_set
*)CFDataGetMutableBytePtr(fdSet
);
338 if (FD_ISSET(sock
, set
)) {
343 CFIndex numFds
= NBBY
* CFDataGetLength(fdSet
);
346 fds_bits
= (fd_mask
*)CFDataGetMutableBytePtr(fdSet
);
347 if (FD_ISSET(sock
, (fd_set
*)fds_bits
)) {
349 FD_CLR(sock
, (fd_set
*)fds_bits
);
357 static SInt32
__CFSocketCreateWakeupSocketPair(void) {
358 #if defined(CFSOCKET_USE_SOCKETPAIR)
359 return socketpair(PF_LOCAL
, SOCK_DGRAM
, 0, __CFWakeupSocketPair
);
361 //??? should really use native Win32 facilities
364 struct sockaddr_in address
[2];
365 int namelen
= sizeof(struct sockaddr_in
);
366 for (i
= 0; i
< 2; i
++) {
367 __CFWakeupSocketPair
[i
] = socket(PF_INET
, SOCK_DGRAM
, 0);
368 memset(&(address
[i
]), 0, sizeof(struct sockaddr_in
));
369 address
[i
].sin_family
= AF_INET
;
370 address
[i
].sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
371 if (0 <= error
) error
= bind(__CFWakeupSocketPair
[i
], (struct sockaddr
*)&(address
[i
]), sizeof(struct sockaddr_in
));
372 if (0 <= error
) error
= getsockname(__CFWakeupSocketPair
[i
], (struct sockaddr
*)&(address
[i
]), &namelen
);
373 if (sizeof(struct sockaddr_in
) != namelen
) error
= -1;
375 if (0 <= error
) error
= connect(__CFWakeupSocketPair
[0], (struct sockaddr
*)&(address
[1]), sizeof(struct sockaddr_in
));
376 if (0 <= error
) error
= connect(__CFWakeupSocketPair
[1], (struct sockaddr
*)&(address
[0]), sizeof(struct sockaddr_in
));
378 closesocket(__CFWakeupSocketPair
[0]);
379 closesocket(__CFWakeupSocketPair
[1]);
380 __CFWakeupSocketPair
[0] = INVALID_SOCKET
;
381 __CFWakeupSocketPair
[1] = INVALID_SOCKET
;
387 #if defined(USE_V1_RUN_LOOP_SOURCE)
388 // Version 1 RunLoopSources set a mask in a Windows System Event to control what socket activity we
389 // hear about. Because you can only set the mask as a whole, we must remember the previous value so
390 // set can make relative changes to it. The way we enable/disable precludes calculating the whole
391 // mask from scratch from the current state we keep.
393 static Boolean
__CFSocketSetWholeEventMask(CFSocketRef s
, long newMask
) {
394 if (s
->_oldEventMask
!= newMask
) {
396 #if defined(LOG_CFSOCKET)
397 fprintf(stdout
, "calling WSAEventSelect for socket/event %d/%d with event flags 0x%lx\n", s
->_socket
, (int)s
->_event
, newMask
);
399 err
= WSAEventSelect(s
->_socket
, s
->_event
, newMask
);
400 CFAssert2(0 == err
, __kCFLogAssertion
, "%s(): WSAEventSelect failed: %d", __PRETTY_FUNCTION__
, WSAGetLastError());
401 s
->_oldEventMask
= newMask
;
407 CF_INLINE Boolean
__CFSocketSetFDForRead(CFSocketRef s
) {
409 // we assume that some read bits are set - all callers have checked this
410 CFAssert1(0 != __CFSocketReadCallBackType(s
), __kCFLogAssertion
, "%s(): __CFSocketReadCallBackType is zero", __PRETTY_FUNCTION__
);
411 bitToSet
= (__CFSocketReadCallBackType(s
) == kCFSocketAcceptCallBack
) ? FD_ACCEPT
: FD_READ
;
412 return __CFSocketSetWholeEventMask(s
, s
->_oldEventMask
| bitToSet
);
415 CF_INLINE Boolean
__CFSocketClearFDForRead(CFSocketRef s
) {
417 // we assume that some read bits are set - all callers have checked this
418 CFAssert1(0 != __CFSocketReadCallBackType(s
), __kCFLogAssertion
, "%s(): __CFSocketReadCallBackType is zero", __PRETTY_FUNCTION__
);
419 bitToClear
= (__CFSocketReadCallBackType(s
) == kCFSocketAcceptCallBack
) ? FD_ACCEPT
: FD_READ
;
420 return __CFSocketSetWholeEventMask(s
, s
->_oldEventMask
& ~bitToClear
);
423 #else // !USE_V1_RUN_LOOP_SOURCE
424 // Version 0 RunLoopSources set a mask in an FD set to control what socket activity we hear about.
425 CF_INLINE Boolean
__CFSocketSetFDForRead(CFSocketRef s
) {
426 return __CFSocketFdSet(s
->_socket
, __CFReadSocketsFds
);
429 CF_INLINE Boolean
__CFSocketClearFDForRead(CFSocketRef s
) {
430 return __CFSocketFdClr(s
->_socket
, __CFReadSocketsFds
);
434 CF_INLINE Boolean
__CFSocketSetFDForWrite(CFSocketRef s
) {
435 return __CFSocketFdSet(s
->_socket
, __CFWriteSocketsFds
);
438 CF_INLINE Boolean
__CFSocketClearFDForWrite(CFSocketRef s
) {
439 return __CFSocketFdClr(s
->_socket
, __CFWriteSocketsFds
);
442 #if defined(USE_V1_RUN_LOOP_SOURCE)
443 static Boolean
__CFSocketCanAcceptBytes(CFSocketRef s
) {
444 struct timeval timeout
= {0, 0};
448 FD_SET(s
->_socket
, &set
);
449 result
= select(s
->_socket
+ 1, NULL
, &set
, NULL
, &timeout
);
450 #if defined(LOG_CFSOCKET)
451 fprintf(stdout
, "polling writability of %d yields %d\n", s
->_socket
, result
);
456 static Boolean
__CFSocketHasBytesToRead(CFSocketRef s
) {
458 int err
= ioctlsocket(s
->_socket
, FIONREAD
, &avail
);
459 CFAssert3(0 == err
, __kCFLogAssertion
, "%s(): unexpected error from ioctlsocket(%d, FIONREAD,...): %d", __PRETTY_FUNCTION__
, s
->_socket
, WSAGetLastError());
460 #if defined(LOG_CFSOCKET)
461 fprintf(stdout
, "polling readability of %d yields %ld\n", s
->_socket
, avail
);
463 return (0 == err
) && avail
> 0;
467 #if defined(__WIN32__)
468 static Boolean WinSockUsed
= FALSE
;
470 static void __CFSocketInitializeWinSock_Guts(void) {
473 WORD versionRequested
= MAKEWORD(2, 0);
475 int errorStatus
= WSAStartup(versionRequested
, &wsaData
);
476 if (errorStatus
!= 0 || LOBYTE(wsaData
.wVersion
) != LOBYTE(versionRequested
) || HIBYTE(wsaData
.wVersion
) != HIBYTE(versionRequested
)) {
478 CFLog(0, CFSTR("*** Could not initialize WinSock subsystem!!!"));
483 CF_EXPORT
void __CFSocketInitializeWinSock(void) {
484 __CFSpinLock(&__CFActiveSocketsLock
);
485 __CFSocketInitializeWinSock_Guts();
486 __CFSpinUnlock(&__CFActiveSocketsLock
);
489 __private_extern__
void __CFSocketCleanup(void) {
490 __CFSpinLock(&__CFActiveSocketsLock
);
491 if (NULL
!= __CFReadSockets
) {
492 CFRelease(__CFWriteSockets
);
493 __CFWriteSockets
= NULL
;
494 CFRelease(__CFReadSockets
);
495 __CFReadSockets
= NULL
;
496 CFRelease(__CFWriteSocketsFds
);
497 __CFWriteSocketsFds
= NULL
;
498 CFRelease(__CFReadSocketsFds
);
499 __CFReadSocketsFds
= NULL
;
500 CFRelease(__CFExceptSocketsFds
);
501 __CFExceptSocketsFds
= NULL
;
502 CFRelease(zeroLengthData
);
503 zeroLengthData
= NULL
;
505 if (NULL
!= __CFAllSockets
) {
506 CFRelease(__CFAllSockets
);
507 __CFAllSockets
= NULL
;
509 if (INVALID_SOCKET
!= __CFWakeupSocketPair
[0]) {
510 closesocket(__CFWakeupSocketPair
[0]);
511 __CFWakeupSocketPair
[0] = INVALID_SOCKET
;
513 if (INVALID_SOCKET
!= __CFWakeupSocketPair
[1]) {
514 closesocket(__CFWakeupSocketPair
[1]);
515 __CFWakeupSocketPair
[1] = INVALID_SOCKET
;
520 __CFSpinUnlock(&__CFActiveSocketsLock
);
524 // CFNetwork needs to call this, especially for Win32 to get WSAStartup
525 static void __CFSocketInitializeSockets(void) {
526 __CFWriteSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
);
527 __CFReadSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
);
528 __CFWriteSocketsFds
= CFDataCreateMutable(kCFAllocatorSystemDefault
, 0);
529 __CFReadSocketsFds
= CFDataCreateMutable(kCFAllocatorSystemDefault
, 0);
530 zeroLengthData
= CFDataCreateMutable(kCFAllocatorSystemDefault
, 0);
531 #if defined(__WIN32__)
532 __CFSocketInitializeWinSock_Guts();
533 // make sure we have space for the count field and the first socket
534 CFDataIncreaseLength(__CFWriteSocketsFds
, sizeof(u_int
) + sizeof(SOCKET
));
535 CFDataIncreaseLength(__CFReadSocketsFds
, sizeof(u_int
) + sizeof(SOCKET
));
536 __CFExceptSocketsFds
= CFDataCreateMutable(kCFAllocatorSystemDefault
, 0);
537 CFDataIncreaseLength(__CFExceptSocketsFds
, sizeof(u_int
) + sizeof(SOCKET
));
539 if (0 > __CFSocketCreateWakeupSocketPair()) {
540 CFLog(0, CFSTR("*** Could not create wakeup socket pair for CFSocket!!!"));
543 /* wakeup sockets must be non-blocking */
544 ioctlsocket(__CFWakeupSocketPair
[0], FIONBIO
, &yes
);
545 ioctlsocket(__CFWakeupSocketPair
[1], FIONBIO
, &yes
);
546 __CFSocketFdSet(__CFWakeupSocketPair
[1], __CFReadSocketsFds
);
550 static CFRunLoopRef
__CFSocketCopyRunLoopToWakeUp(CFSocketRef s
) {
551 CFRunLoopRef rl
= NULL
;
552 SInt32 idx
, cnt
= CFArrayGetCount(s
->_runLoops
);
554 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(s
->_runLoops
, 0);
555 for (idx
= 1; NULL
!= rl
&& idx
< cnt
; idx
++) {
556 CFRunLoopRef value
= (CFRunLoopRef
)CFArrayGetValueAtIndex(s
->_runLoops
, idx
);
557 if (value
!= rl
) rl
= NULL
;
559 if (NULL
== rl
) { /* more than one different rl, so we must pick one */
560 /* ideally, this would be a run loop which isn't also in a
561 * signaled state for this or another source, but that's tricky;
562 * we pick one that is running in an appropriate mode for this
563 * source, and from those if possible one that is waiting; then
564 * we move this run loop to the end of the list to scramble them
565 * a bit, and always search from the front */
566 Boolean foundIt
= false, foundBackup
= false;
568 for (idx
= 0; !foundIt
&& idx
< cnt
; idx
++) {
569 CFRunLoopRef value
= (CFRunLoopRef
)CFArrayGetValueAtIndex(s
->_runLoops
, idx
);
570 CFStringRef currentMode
= CFRunLoopCopyCurrentMode(value
);
571 if (NULL
!= currentMode
) {
572 if (CFRunLoopContainsSource(value
, s
->_source0
, currentMode
)) {
573 if (CFRunLoopIsWaiting(value
)) {
576 } else if (!foundBackup
) {
581 CFRelease(currentMode
);
584 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(s
->_runLoops
, foundIdx
);
586 CFArrayRemoveValueAtIndex(s
->_runLoops
, foundIdx
);
587 CFArrayAppendValue(s
->_runLoops
, rl
);
595 // If callBackNow, we immediately do client callbacks, else we have to signal a v0 RunLoopSource so the
596 // callbacks can happen in another thread.
597 static void __CFSocketHandleWrite(CFSocketRef s
, Boolean callBackNow
) {
598 SInt32 errorCode
= 0;
599 int errorSize
= sizeof(errorCode
);
600 CFOptionFlags writeCallBacksAvailable
;
602 if (!CFSocketIsValid(s
)) return;
603 if (0 != getsockopt(s
->_socket
, SOL_SOCKET
, SO_ERROR
, (void *)&errorCode
, &errorSize
)) errorCode
= 0; // cast for WinSock bad API
604 #if defined(LOG_CFSOCKET)
605 if (errorCode
) fprintf(stdout
, "error %ld on socket %d\n", errorCode
, s
->_socket
);
608 writeCallBacksAvailable
= __CFSocketCallBackTypes(s
) & (kCFSocketWriteCallBack
| kCFSocketConnectCallBack
);
609 if ((s
->_f
.client
& kCFSocketConnectCallBack
) != 0) writeCallBacksAvailable
&= ~kCFSocketConnectCallBack
;
610 if (!__CFSocketIsValid(s
) || ((s
->_f
.disabled
& writeCallBacksAvailable
) == writeCallBacksAvailable
)) {
614 s
->_errorCode
= errorCode
;
615 __CFSocketSetWriteSignalled(s
);
616 #if defined(LOG_CFSOCKET)
617 fprintf(stdout
, "write signaling source for socket %d\n", s
->_socket
);
620 __CFSocketDoCallback(s
, NULL
, NULL
, 0);
623 CFRunLoopSourceSignal(s
->_source0
);
624 rl
= __CFSocketCopyRunLoopToWakeUp(s
);
633 static void __CFSocketHandleRead(CFSocketRef s
) {
634 CFDataRef data
= NULL
, address
= NULL
;
635 CFSocketNativeHandle sock
= INVALID_SOCKET
;
636 if (!CFSocketIsValid(s
)) return;
637 if (__CFSocketReadCallBackType(s
) == kCFSocketDataCallBack
) {
638 uint8_t buffer
[MAX_DATA_SIZE
];
639 uint8_t name
[MAX_SOCKADDR_LEN
];
640 int namelen
= sizeof(name
);
641 SInt32 recvlen
= recvfrom(s
->_socket
, buffer
, sizeof(buffer
), 0, (struct sockaddr
*)name
, &namelen
);
642 #if defined(LOG_CFSOCKET)
643 fprintf(stdout
, "read %ld bytes on socket %d\n", recvlen
, s
->_socket
);
646 //??? should return error if <0
647 /* zero-length data is the signal for perform to invalidate */
648 data
= CFRetain(zeroLengthData
);
650 data
= CFDataCreate(CFGetAllocator(s
), buffer
, recvlen
);
653 if (!__CFSocketIsValid(s
)) {
658 __CFSocketSetReadSignalled(s
);
659 if (NULL
!= name
&& 0 < namelen
) {
660 //??? possible optimizations: uniquing; storing last value
661 address
= CFDataCreate(CFGetAllocator(s
), name
, namelen
);
662 } else if (__CFSocketIsConnectionOriented(s
)) {
663 if (NULL
== s
->_peerAddress
) __CFSocketEstablishPeerAddress(s
);
664 if (NULL
!= s
->_peerAddress
) address
= CFRetain(s
->_peerAddress
);
666 if (NULL
== address
) {
667 address
= CFRetain(zeroLengthData
);
669 #if !defined(USE_V1_RUN_LOOP_SOURCE)
670 if (NULL
== s
->_dataQueue
) {
671 s
->_dataQueue
= CFArrayCreateMutable(CFGetAllocator(s
), 0, &kCFTypeArrayCallBacks
);
673 if (NULL
== s
->_addressQueue
) {
674 s
->_addressQueue
= CFArrayCreateMutable(CFGetAllocator(s
), 0, &kCFTypeArrayCallBacks
);
676 CFArrayAppendValue(s
->_dataQueue
, data
);
678 CFArrayAppendValue(s
->_addressQueue
, address
);
680 #endif // !USE_V1_RUN_LOOP_SOURCE
682 && (s
->_f
.client
& kCFSocketDataCallBack
) != 0 && (s
->_f
.disabled
& kCFSocketDataCallBack
) == 0
683 && __CFSocketIsScheduled(s
)
684 #if !defined(USE_V1_RUN_LOOP_SOURCE)
685 && (0 == s
->_maxQueueLen
|| CFArrayGetCount(s
->_dataQueue
) < s
->_maxQueueLen
)
686 #endif // !USE_V1_RUN_LOOP_SOURCE
688 __CFSpinLock(&__CFActiveSocketsLock
);
689 /* restore socket to fds */
690 __CFSocketSetFDForRead(s
);
691 __CFSpinUnlock(&__CFActiveSocketsLock
);
693 } else if (__CFSocketReadCallBackType(s
) == kCFSocketAcceptCallBack
) {
694 uint8_t name
[MAX_SOCKADDR_LEN
];
695 int namelen
= sizeof(name
);
696 sock
= accept(s
->_socket
, (struct sockaddr
*)name
, &namelen
);
697 if (INVALID_SOCKET
== sock
) {
698 //??? should return error
701 if (NULL
!= name
&& 0 < namelen
) {
702 address
= CFDataCreate(CFGetAllocator(s
), name
, namelen
);
704 address
= CFRetain(zeroLengthData
);
707 if (!__CFSocketIsValid(s
)) {
713 __CFSocketSetReadSignalled(s
);
714 #if !defined(USE_V1_RUN_LOOP_SOURCE)
715 if (NULL
== s
->_dataQueue
) {
716 s
->_dataQueue
= CFArrayCreateMutable(CFGetAllocator(s
), 0, NULL
);
718 if (NULL
== s
->_addressQueue
) {
719 s
->_addressQueue
= CFArrayCreateMutable(CFGetAllocator(s
), 0, &kCFTypeArrayCallBacks
);
721 CFArrayAppendValue(s
->_dataQueue
, (void *)sock
);
722 CFArrayAppendValue(s
->_addressQueue
, address
);
724 #endif // !USE_V1_RUN_LOOP_SOURCE
725 if ((s
->_f
.client
& kCFSocketAcceptCallBack
) != 0 && (s
->_f
.disabled
& kCFSocketAcceptCallBack
) == 0
726 && __CFSocketIsScheduled(s
)
727 #if !defined(USE_V1_RUN_LOOP_SOURCE)
728 && (0 == s
->_maxQueueLen
|| CFArrayGetCount(s
->_dataQueue
) < s
->_maxQueueLen
)
729 #endif // !USE_V1_RUN_LOOP_SOURCE
731 __CFSpinLock(&__CFActiveSocketsLock
);
732 /* restore socket to fds */
733 __CFSocketSetFDForRead(s
);
734 __CFSpinUnlock(&__CFActiveSocketsLock
);
738 if (!__CFSocketIsValid(s
) || (s
->_f
.disabled
& kCFSocketReadCallBack
) != 0) {
742 __CFSocketSetReadSignalled(s
);
744 #if defined(LOG_CFSOCKET)
745 fprintf(stdout
, "read signaling source for socket %d\n", s
->_socket
);
747 #if defined(USE_V1_RUN_LOOP_SOURCE)
748 // since in the v0 case data and sock come from the same queue, only one could be set
749 CFAssert1(NULL
== data
|| 0 == sock
, __kCFLogAssertion
, "%s(): both data and sock are set", __PRETTY_FUNCTION__
);
750 __CFSocketDoCallback(s
, data
, address
, sock
); // does __CFSocketUnlock(s)
751 if (NULL
!= data
) CFRelease(data
);
752 if (NULL
!= address
) CFRelease(address
);
754 CFRunLoopSourceSignal(s
->_source0
);
755 CFRunLoopRef rl
= __CFSocketCopyRunLoopToWakeUp(s
);
761 #endif // !USE_V1_RUN_LOOP_SOURCE
764 #if defined(LOG_CFSOCKET)
765 static void __CFSocketWriteSocketList(CFArrayRef sockets
, CFDataRef fdSet
, Boolean onlyIfSet
) {
766 fd_set
*tempfds
= (fd_set
*)CFDataGetBytePtr(fdSet
);
768 for (idx
= 0, cnt
= CFArrayGetCount(sockets
); idx
< cnt
; idx
++) {
769 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(sockets
, idx
);
770 if (FD_ISSET(s
->_socket
, tempfds
)) {
771 fprintf(stdout
, "%d ", s
->_socket
);
772 } else if (!onlyIfSet
) {
773 fprintf(stdout
, "(%d) ", s
->_socket
);
780 __attribute__ ((noreturn
)) // mostly interesting for shutting up a warning
782 static void __CFSocketManager(void * arg
)
784 SInt32 nrfds
, maxnrfds
, fdentries
= 1;
786 #if defined(__WIN32__)
787 fd_set
*exceptfds
= (fd_set
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, fdentries
* sizeof(SOCKET
) + sizeof(u_int
), 0);
788 fd_set
*writefds
= (fd_set
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, fdentries
* sizeof(SOCKET
) + sizeof(u_int
), 0);
789 fd_set
*readfds
= (fd_set
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, fdentries
* sizeof(SOCKET
) + sizeof(u_int
), 0);
791 fd_set
*exceptfds
= NULL
;
792 fd_set
*writefds
= (fd_set
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, fdentries
* sizeof(fd_mask
), 0);
793 fd_set
*readfds
= (fd_set
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, fdentries
* sizeof(fd_mask
), 0);
798 CFMutableArrayRef selectedWriteSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
799 CFMutableArrayRef selectedReadSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
802 __CFSpinLock(&__CFActiveSocketsLock
);
803 __CFSocketManagerIteration
++;
804 #if defined(LOG_CFSOCKET)
805 fprintf(stdout
, "socket manager iteration %lu looking at read sockets ", __CFSocketManagerIteration
);
806 __CFSocketWriteSocketList(__CFReadSockets
, __CFReadSocketsFds
, FALSE
);
807 if (0 < CFArrayGetCount(__CFWriteSockets
)) {
808 fprintf(stdout
, " and write sockets ");
809 __CFSocketWriteSocketList(__CFWriteSockets
, __CFWriteSocketsFds
, FALSE
);
810 #if defined(__WIN32__)
811 fprintf(stdout
, " and except sockets ");
812 __CFSocketWriteSocketList(__CFWriteSockets
, __CFExceptSocketsFds
, TRUE
);
815 fprintf(stdout
, "\n");
817 rfds
= __CFSocketFdGetSize(__CFReadSocketsFds
);
818 wfds
= __CFSocketFdGetSize(__CFWriteSocketsFds
);
819 maxnrfds
= __CFMax(rfds
, wfds
);
820 #if defined(__WIN32__)
821 if (maxnrfds
> fdentries
) {
822 fdentries
= maxnrfds
;
823 exceptfds
= (fd_set
*)CFAllocatorReallocate(kCFAllocatorSystemDefault
, exceptfds
, fdentries
* sizeof(SOCKET
) + sizeof(u_int
), 0);
824 writefds
= (fd_set
*)CFAllocatorReallocate(kCFAllocatorSystemDefault
, writefds
, fdentries
* sizeof(SOCKET
) + sizeof(u_int
), 0);
825 readfds
= (fd_set
*)CFAllocatorReallocate(kCFAllocatorSystemDefault
, readfds
, fdentries
* sizeof(SOCKET
) + sizeof(u_int
), 0);
827 memset(exceptfds
, 0, fdentries
* sizeof(SOCKET
) + sizeof(u_int
));
828 memset(writefds
, 0, fdentries
* sizeof(SOCKET
) + sizeof(u_int
));
829 memset(readfds
, 0, fdentries
* sizeof(SOCKET
) + sizeof(u_int
));
830 CFDataGetBytes(__CFExceptSocketsFds
, CFRangeMake(0, __CFSocketFdGetSize(__CFExceptSocketsFds
) * sizeof(SOCKET
) + sizeof(u_int
)), (UInt8
*)exceptfds
);
831 CFDataGetBytes(__CFWriteSocketsFds
, CFRangeMake(0, wfds
* sizeof(SOCKET
) + sizeof(u_int
)), (UInt8
*)writefds
);
832 CFDataGetBytes(__CFReadSocketsFds
, CFRangeMake(0, rfds
* sizeof(SOCKET
) + sizeof(u_int
)), (UInt8
*)readfds
);
834 if (maxnrfds
> fdentries
* (int)NFDBITS
) {
835 fdentries
= (maxnrfds
+ NFDBITS
- 1) / NFDBITS
;
836 writefds
= (fd_set
*)CFAllocatorReallocate(kCFAllocatorSystemDefault
, writefds
, fdentries
* sizeof(fd_mask
), 0);
837 readfds
= (fd_set
*)CFAllocatorReallocate(kCFAllocatorSystemDefault
, readfds
, fdentries
* sizeof(fd_mask
), 0);
839 memset(writefds
, 0, fdentries
* sizeof(fd_mask
));
840 memset(readfds
, 0, fdentries
* sizeof(fd_mask
));
841 CFDataGetBytes(__CFWriteSocketsFds
, CFRangeMake(0, CFDataGetLength(__CFWriteSocketsFds
)), (UInt8
*)writefds
);
842 CFDataGetBytes(__CFReadSocketsFds
, CFRangeMake(0, CFDataGetLength(__CFReadSocketsFds
)), (UInt8
*)readfds
);
844 __CFSpinUnlock(&__CFActiveSocketsLock
);
846 nrfds
= select(maxnrfds
, readfds
, writefds
, exceptfds
, NULL
);
847 #if defined(LOG_CFSOCKET)
848 fprintf(stdout
, "socket manager woke from select, ret=%ld\n", nrfds
);
850 if (0 == nrfds
) continue;
852 SInt32 selectError
= __CFSocketLastError();
853 #if defined(LOG_CFSOCKET)
854 fprintf(stdout
, "socket manager received error %ld from select\n", selectError
);
856 if (EBADF
== selectError
) {
857 CFMutableArrayRef invalidSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
858 __CFSpinLock(&__CFActiveSocketsLock
);
859 cnt
= CFArrayGetCount(__CFWriteSockets
);
860 for (idx
= 0; idx
< cnt
; idx
++) {
861 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFWriteSockets
, idx
);
862 if (!__CFNativeSocketIsValid(s
->_socket
)) {
863 #if defined(LOG_CFSOCKET)
864 fprintf(stdout
, "socket manager found write socket %d invalid\n", s
->_socket
);
866 CFArrayAppendValue(invalidSockets
, s
);
869 cnt
= CFArrayGetCount(__CFReadSockets
);
870 for (idx
= 0; idx
< cnt
; idx
++) {
871 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFReadSockets
, idx
);
872 if (!__CFNativeSocketIsValid(s
->_socket
)) {
873 #if defined(LOG_CFSOCKET)
874 fprintf(stdout
, "socket manager found read socket %d invalid\n", s
->_socket
);
876 CFArrayAppendValue(invalidSockets
, s
);
879 __CFSpinUnlock(&__CFActiveSocketsLock
);
881 cnt
= CFArrayGetCount(invalidSockets
);
882 for (idx
= 0; idx
< cnt
; idx
++) {
883 __CFSocketInvalidate(((CFSocketRef
)CFArrayGetValueAtIndex(invalidSockets
, idx
)), false);
885 CFRelease(invalidSockets
);
889 if (FD_ISSET(__CFWakeupSocketPair
[1], readfds
)) {
890 recv(__CFWakeupSocketPair
[1], buffer
, sizeof(buffer
), 0);
891 #if defined(LOG_CFSOCKET)
892 fprintf(stdout
, "socket manager received %c on wakeup socket\n", buffer
[0]);
895 __CFSpinLock(&__CFActiveSocketsLock
);
897 cnt
= CFArrayGetCount(__CFWriteSockets
);
898 for (idx
= 0; idx
< cnt
; idx
++) {
899 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFWriteSockets
, idx
);
900 CFSocketNativeHandle sock
= s
->_socket
;
901 #if !defined(__WIN32__)
902 // We might have an new element in __CFWriteSockets that we weren't listening to,
903 // in which case we must be sure not to test a bit in the fdset that is
904 // outside our mask size.
905 Boolean sockInBounds
= (0 <= sock
&& sock
< maxnrfds
);
907 // fdset's are arrays, so we don't have that issue above
908 Boolean sockInBounds
= true;
910 if (INVALID_SOCKET
!= sock
&& sockInBounds
) {
911 if (FD_ISSET(sock
, writefds
)) {
912 CFArrayAppendValue(selectedWriteSockets
, s
);
913 /* socket is removed from fds here, restored by CFSocketReschedule */
914 if (!tempfds
) tempfds
= (fd_set
*)CFDataGetMutableBytePtr(__CFWriteSocketsFds
);
915 FD_CLR(sock
, tempfds
);
916 #if defined(__WIN32__)
917 fd_set
*exfds
= (fd_set
*)CFDataGetMutableBytePtr(__CFExceptSocketsFds
);
921 #if defined(__WIN32__)
922 else if (FD_ISSET(sock
, exceptfds
)) {
923 // On Win32 connect errors come in on exceptFDs. We treat these as if
924 // they had come on writeFDs, since the rest of our Unix-based code
926 CFArrayAppendValue(selectedWriteSockets
, s
);
927 fd_set
*exfds
= (fd_set
*)CFDataGetMutableBytePtr(__CFExceptSocketsFds
);
934 cnt
= CFArrayGetCount(__CFReadSockets
);
935 for (idx
= 0; idx
< cnt
; idx
++) {
936 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFReadSockets
, idx
);
937 CFSocketNativeHandle sock
= s
->_socket
;
938 #if !defined(__WIN32__)
939 // We might have an new element in __CFReadSockets that we weren't listening to,
940 // in which case we must be sure not to test a bit in the fdset that is
941 // outside our mask size.
942 Boolean sockInBounds
= (0 <= sock
&& sock
< maxnrfds
);
944 // fdset's are arrays, so we don't have that issue above
945 Boolean sockInBounds
= true;
947 if (INVALID_SOCKET
!= sock
&& sockInBounds
&& FD_ISSET(sock
, readfds
)) {
948 CFArrayAppendValue(selectedReadSockets
, s
);
949 /* socket is removed from fds here, will be restored in read handling or in perform function */
950 if (!tempfds
) tempfds
= (fd_set
*)CFDataGetMutableBytePtr(__CFReadSocketsFds
);
951 FD_CLR(sock
, tempfds
);
954 __CFSpinUnlock(&__CFActiveSocketsLock
);
956 cnt
= CFArrayGetCount(selectedWriteSockets
);
957 for (idx
= 0; idx
< cnt
; idx
++) {
958 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(selectedWriteSockets
, idx
);
959 #if defined(LOG_CFSOCKET)
960 fprintf(stdout
, "socket manager signaling socket %d for write\n", s
->_socket
);
962 __CFSocketHandleWrite(s
, FALSE
);
964 if (0 < cnt
) CFArrayRemoveAllValues(selectedWriteSockets
);
965 cnt
= CFArrayGetCount(selectedReadSockets
);
966 for (idx
= 0; idx
< cnt
; idx
++) {
967 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(selectedReadSockets
, idx
);
968 #if defined(LOG_CFSOCKET)
969 fprintf(stdout
, "socket manager signaling socket %d for read\n", s
->_socket
);
971 __CFSocketHandleRead(s
);
973 if (0 < cnt
) CFArrayRemoveAllValues(selectedReadSockets
);
977 static CFStringRef
__CFSocketCopyDescription(CFTypeRef cf
) {
978 CFSocketRef s
= (CFSocketRef
)cf
;
979 CFMutableStringRef result
;
980 CFStringRef contextDesc
= NULL
;
981 void *contextInfo
= NULL
;
982 CFStringRef (*contextCopyDescription
)(const void *info
) = NULL
;
983 result
= CFStringCreateMutable(CFGetAllocator(s
), 0);
985 CFStringAppendFormat(result
, NULL
, CFSTR("<CFSocket %p [%p]>{valid = %s, type = %d, socket = %d, socket set count = %ld\n callback types = 0x%x, callout = %x, source = %p,\n run loops = %@,\n context = "), cf
, CFGetAllocator(s
), (__CFSocketIsValid(s
) ? "Yes" : "No"), s
->_socketType
, s
->_socket
, s
->_socketSetCount
, __CFSocketCallBackTypes(s
), s
->_callout
, s
->_source0
, s
->_runLoops
);
986 contextInfo
= s
->_context
.info
;
987 contextCopyDescription
= s
->_context
.copyDescription
;
989 if (NULL
!= contextInfo
&& NULL
!= contextCopyDescription
) {
990 contextDesc
= (CFStringRef
)contextCopyDescription(contextInfo
);
992 if (NULL
== contextDesc
) {
993 contextDesc
= CFStringCreateWithFormat(CFGetAllocator(s
), NULL
, CFSTR("<CFSocket context %p>"), contextInfo
);
995 CFStringAppend(result
, contextDesc
);
996 CFRelease(contextDesc
);
1000 static void __CFSocketDeallocate(CFTypeRef cf
) {
1001 /* Since CFSockets are cached, we can only get here sometime after being invalidated */
1002 CFSocketRef s
= (CFSocketRef
)cf
;
1003 if (NULL
!= s
->_address
) {
1004 CFRelease(s
->_address
);
1009 static const CFRuntimeClass __CFSocketClass
= {
1014 __CFSocketDeallocate
,
1018 __CFSocketCopyDescription
1021 __private_extern__
void __CFSocketInitialize(void) {
1022 __kCFSocketTypeID
= _CFRuntimeRegisterClass(&__CFSocketClass
);
1025 CFTypeID
CFSocketGetTypeID(void) {
1026 return __kCFSocketTypeID
;
1029 CFSocketError
CFSocketSetAddress(CFSocketRef s
, CFDataRef address
) {
1030 const uint8_t *name
;
1031 SInt32 namelen
, result
= 0;
1032 __CFGenericValidateType(s
, __kCFSocketTypeID
);
1033 if (NULL
== address
) return -1;
1034 name
= CFDataGetBytePtr(address
);
1035 namelen
= CFDataGetLength(address
);
1037 if (__CFSocketIsValid(s
) && INVALID_SOCKET
!= s
->_socket
&& NULL
!= name
&& 0 < namelen
) {
1038 result
= bind(s
->_socket
, (struct sockaddr
*)name
, namelen
);
1040 __CFSocketEstablishAddress(s
);
1041 listen(s
->_socket
, 256);
1044 if (NULL
== s
->_address
&& NULL
!= name
&& 0 < namelen
&& 0 == result
) {
1045 s
->_address
= CFDataCreateCopy(CFGetAllocator(s
), address
);
1047 __CFSocketUnlock(s
);
1048 //??? should return errno
1052 __private_extern__
void CFSocketSetAcceptBacklog(CFSocketRef s
, CFIndex limit
) {
1053 __CFGenericValidateType(s
, __kCFSocketTypeID
);
1055 if (__CFSocketIsValid(s
) && INVALID_SOCKET
!= s
->_socket
) {
1056 listen(s
->_socket
, limit
);
1058 __CFSocketUnlock(s
);
1061 __private_extern__
void CFSocketSetMaximumQueueLength(CFSocketRef s
, CFIndex length
) {
1062 __CFGenericValidateType(s
, __kCFSocketTypeID
);
1063 #if !defined(USE_V1_RUN_LOOP_SOURCE)
1065 if (__CFSocketIsValid(s
)) {
1066 s
->_maxQueueLen
= length
;
1068 __CFSocketUnlock(s
);
1072 CFSocketError
CFSocketConnectToAddress(CFSocketRef s
, CFDataRef address
, CFTimeInterval timeout
) {
1073 //??? need error handling, retries
1074 const uint8_t *name
;
1075 SInt32 namelen
, result
= -1, connect_err
= 0, select_err
= 0;
1076 UInt32 yes
= 1, no
= 0;
1077 Boolean wasBlocking
= true;
1079 __CFGenericValidateType(s
, __kCFSocketTypeID
);
1080 name
= CFDataGetBytePtr(address
);
1081 namelen
= CFDataGetLength(address
);
1083 if (__CFSocketIsValid(s
) && INVALID_SOCKET
!= s
->_socket
&& NULL
!= name
&& 0 < namelen
) {
1084 #if !defined(__WIN32__)
1085 SInt32 flags
= fcntl(s
->_socket
, F_GETFL
, 0);
1086 if (flags
>= 0) wasBlocking
= ((flags
& O_NONBLOCK
) == 0);
1087 if (wasBlocking
&& (timeout
> 0.0 || timeout
< 0.0)) ioctlsocket(s
->_socket
, FIONBIO
, &yes
);
1089 // You can set but not get this flag in WIN32, so assume it was in non-blocking mode.
1090 // The downside is that when we leave this routine we'll leave it non-blocking,
1091 // whether it started that way or not.
1092 if (timeout
> 0.0 || timeout
< 0.0) ioctlsocket(s
->_socket
, FIONBIO
, &yes
);
1093 wasBlocking
= false;
1095 result
= connect(s
->_socket
, (struct sockaddr
*)name
, namelen
);
1097 connect_err
= __CFSocketLastError();
1098 #if defined(__WIN32__)
1099 if (connect_err
== WSAEWOULDBLOCK
) connect_err
= EINPROGRESS
;
1102 #if defined(LOG_CFSOCKET)
1103 #if !defined(__WIN32__)
1104 fprintf(stdout
, "connection attempt returns %ld error %ld on socket %d (flags 0x%lx blocking %d)\n", result
, connect_err
, s
->_socket
, flags
, wasBlocking
);
1106 fprintf(stdout
, "connection attempt returns %ld error %ld on socket %d\n", result
, connect_err
, s
->_socket
);
1109 if (EINPROGRESS
== connect_err
&& timeout
>= 0.0) {
1110 /* select on socket */
1112 int error_size
= sizeof(select_err
);
1114 CFMutableDataRef fds
= CFDataCreateMutable(kCFAllocatorSystemDefault
, 0);
1115 #if defined(__WIN32__)
1116 CFDataIncreaseLength(fds
, sizeof(u_int
) + sizeof(SOCKET
));
1118 __CFSocketFdSet(s
->_socket
, fds
);
1119 tv
.tv_sec
= (0 >= timeout
|| INT_MAX
<= timeout
) ? INT_MAX
: (int)(float)floor(timeout
);
1120 tv
.tv_usec
= (int)((timeout
- floor(timeout
)) * 1.0E6
);
1121 nrfds
= select(__CFSocketFdGetSize(fds
), NULL
, (fd_set
*)CFDataGetMutableBytePtr(fds
), NULL
, &tv
);
1123 select_err
= __CFSocketLastError();
1125 } else if (nrfds
== 0) {
1128 if (0 != getsockopt(s
->_socket
, SOL_SOCKET
, SO_ERROR
, (void *)&select_err
, &error_size
)) select_err
= 0;
1129 result
= (select_err
== 0) ? 0 : -1;
1132 #if defined(LOG_CFSOCKET)
1133 fprintf(stdout
, "timed connection attempt %s on socket %d, result %ld, select returns %ld error %ld\n", (result
== 0) ? "succeeds" : "fails", s
->_socket
, result
, nrfds
, select_err
);
1136 if (wasBlocking
&& (timeout
> 0.0 || timeout
< 0.0)) ioctlsocket(s
->_socket
, FIONBIO
, &no
);
1138 __CFSocketEstablishPeerAddress(s
);
1139 if (NULL
== s
->_peerAddress
&& NULL
!= name
&& 0 < namelen
&& __CFSocketIsConnectionOriented(s
)) {
1140 s
->_peerAddress
= CFDataCreateCopy(CFGetAllocator(s
), address
);
1143 if (EINPROGRESS
== connect_err
&& timeout
< 0.0) {
1145 #if defined(LOG_CFSOCKET)
1146 fprintf(stdout
, "connection attempt continues in background on socket %d\n", s
->_socket
);
1150 __CFSocketUnlock(s
);
1151 //??? should return errno
1155 CFSocketRef
CFSocketCreate(CFAllocatorRef allocator
, SInt32 protocolFamily
, SInt32 socketType
, SInt32 protocol
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
) {
1156 CFSocketNativeHandle sock
= INVALID_SOCKET
;
1157 CFSocketRef s
= NULL
;
1158 if (0 >= protocolFamily
) protocolFamily
= PF_INET
;
1159 if (PF_INET
== protocolFamily
) {
1160 if (0 >= socketType
) socketType
= SOCK_STREAM
;
1161 if (0 >= protocol
&& SOCK_STREAM
== socketType
) protocol
= IPPROTO_TCP
;
1162 if (0 >= protocol
&& SOCK_DGRAM
== socketType
) protocol
= IPPROTO_UDP
;
1164 #if !defined(__WIN32__)
1165 if (PF_LOCAL
== protocolFamily
&& 0 >= socketType
) socketType
= SOCK_STREAM
;
1167 /* WinSock needs to be initialized at this point for Windows, before socket() */
1168 __CFSocketInitializeWinSock();
1170 sock
= socket(protocolFamily
, socketType
, protocol
);
1171 if (INVALID_SOCKET
!= sock
) {
1172 s
= CFSocketCreateWithNative(allocator
, sock
, callBackTypes
, callout
, context
);
1177 CFSocketRef
CFSocketCreateWithNative(CFAllocatorRef allocator
, CFSocketNativeHandle sock
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
) {
1179 int typeSize
= sizeof(memory
->_socketType
);
1180 __CFSpinLock(&__CFActiveSocketsLock
);
1181 if (NULL
== __CFReadSockets
) __CFSocketInitializeSockets();
1182 __CFSpinUnlock(&__CFActiveSocketsLock
);
1183 __CFSpinLock(&__CFAllSocketsLock
);
1184 if (NULL
== __CFAllSockets
) {
1185 __CFAllSockets
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, &kCFTypeDictionaryValueCallBacks
);
1187 if (INVALID_SOCKET
!= sock
&& CFDictionaryGetValueIfPresent(__CFAllSockets
, (void *)sock
, (const void **)&memory
)) {
1188 __CFSpinUnlock(&__CFAllSocketsLock
);
1192 memory
= (CFSocketRef
)_CFRuntimeCreateInstance(allocator
, __kCFSocketTypeID
, sizeof(struct __CFSocket
) - sizeof(CFRuntimeBase
), NULL
);
1193 if (NULL
== memory
) {
1194 __CFSpinUnlock(&__CFAllSocketsLock
);
1197 __CFSocketSetCallBackTypes(memory
, callBackTypes
);
1198 if (INVALID_SOCKET
!= sock
) __CFSocketSetValid(memory
);
1199 __CFSocketUnsetWriteSignalled(memory
);
1200 __CFSocketUnsetReadSignalled(memory
);
1201 memory
->_f
.client
= ((callBackTypes
& (~kCFSocketConnectCallBack
)) & (~kCFSocketWriteCallBack
)) | kCFSocketCloseOnInvalidate
;
1202 memory
->_f
.disabled
= 0;
1203 memory
->_f
.connected
= FALSE
;
1204 memory
->_f
.writableHint
= FALSE
;
1205 memory
->_f
.closeSignaled
= FALSE
;
1207 memory
->_writeLock
= 0;
1208 memory
->_socket
= sock
;
1209 if (INVALID_SOCKET
== sock
|| 0 != getsockopt(sock
, SOL_SOCKET
, SO_TYPE
, (void *)&(memory
->_socketType
), &typeSize
)) memory
->_socketType
= 0; // cast for WinSock bad API
1210 memory
->_errorCode
= 0;
1211 memory
->_address
= NULL
;
1212 memory
->_peerAddress
= NULL
;
1213 memory
->_socketSetCount
= 0;
1214 memory
->_source0
= NULL
;
1215 if (INVALID_SOCKET
!= sock
) {
1216 memory
->_runLoops
= CFArrayCreateMutable(allocator
, 0, NULL
);
1218 memory
->_runLoops
= NULL
;
1220 memory
->_callout
= callout
;
1221 #if defined(USE_V1_RUN_LOOP_SOURCE)
1222 memory
->_event
= CreateEvent(NULL
, true, false, NULL
);
1223 CFAssert1(NULL
!= memory
->_event
, __kCFLogAssertion
, "%s(): could not create event", __PRETTY_FUNCTION__
);
1224 memory
->_oldEventMask
= 0;
1225 __CFSocketSetWholeEventMask(memory
, FD_CLOSE
|FD_CONNECT
); // always listen for closes, connects
1226 memory
->_source1
= NULL
;
1227 #else // !USE_V1_RUN_LOOP_SOURCE
1228 memory
->_dataQueue
= NULL
;
1229 memory
->_addressQueue
= NULL
;
1230 memory
->_maxQueueLen
= 0;
1231 #endif // !USE_V1_RUN_LOOP_SOURCE
1232 memory
->_context
.info
= 0;
1233 memory
->_context
.retain
= 0;
1234 memory
->_context
.release
= 0;
1235 memory
->_context
.copyDescription
= 0;
1236 if (INVALID_SOCKET
!= sock
) CFDictionaryAddValue(__CFAllSockets
, (void *)sock
, memory
);
1237 __CFSpinUnlock(&__CFAllSocketsLock
);
1238 if (NULL
!= context
) {
1239 void *contextInfo
= context
->retain
? (void *)context
->retain(context
->info
) : context
->info
;
1240 __CFSocketLock(memory
);
1241 memory
->_context
.retain
= context
->retain
;
1242 memory
->_context
.release
= context
->release
;
1243 memory
->_context
.copyDescription
= context
->copyDescription
;
1244 memory
->_context
.info
= contextInfo
;
1245 __CFSocketUnlock(memory
);
1250 CFSocketRef
CFSocketCreateWithSocketSignature(CFAllocatorRef allocator
, const CFSocketSignature
*signature
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
) {
1251 CFSocketRef s
= CFSocketCreate(allocator
, signature
->protocolFamily
, signature
->socketType
, signature
->protocol
, callBackTypes
, callout
, context
);
1252 if (NULL
!= s
&& (!CFSocketIsValid(s
) || kCFSocketSuccess
!= CFSocketSetAddress(s
, signature
->address
))) {
1253 CFSocketInvalidate(s
);
1260 CFSocketRef
CFSocketCreateConnectedToSocketSignature(CFAllocatorRef allocator
, const CFSocketSignature
*signature
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
, CFTimeInterval timeout
) {
1261 CFSocketRef s
= CFSocketCreate(allocator
, signature
->protocolFamily
, signature
->socketType
, signature
->protocol
, callBackTypes
, callout
, context
);
1262 if (NULL
!= s
&& (!CFSocketIsValid(s
) || kCFSocketSuccess
!= CFSocketConnectToAddress(s
, signature
->address
, timeout
))) {
1263 CFSocketInvalidate(s
);
1270 static void __CFSocketInvalidate(CFSocketRef s
, Boolean wakeup
) {
1271 UInt32 previousSocketManagerIteration
;
1272 __CFGenericValidateType(s
, __kCFSocketTypeID
);
1273 #if defined(LOG_CFSOCKET)
1274 fprintf(stdout
, "invalidating socket %d with flags 0x%x disabled 0x%x connected 0x%x wakeup %d\n", s
->_socket
, s
->_f
.client
, s
->_f
.disabled
, s
->_f
.connected
, wakeup
);
1277 __CFSpinLock(&__CFAllSocketsLock
);
1279 if (__CFSocketIsValid(s
)) {
1281 CFRunLoopSourceRef source0
;
1282 void *contextInfo
= NULL
;
1283 void (*contextRelease
)(const void *info
) = NULL
;
1284 __CFSocketUnsetValid(s
);
1285 __CFSocketUnsetWriteSignalled(s
);
1286 __CFSocketUnsetReadSignalled(s
);
1287 __CFSpinLock(&__CFActiveSocketsLock
);
1288 idx
= CFArrayGetFirstIndexOfValue(__CFWriteSockets
, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets
)), s
);
1290 CFArrayRemoveValueAtIndex(__CFWriteSockets
, idx
);
1291 __CFSocketClearFDForWrite(s
);
1292 #if defined(__WIN32__)
1293 __CFSocketFdClr(s
->_socket
, __CFExceptSocketsFds
);
1296 #if !defined(USE_V1_RUN_LOOP_SOURCE)
1297 // No need to clear FD's for V1 sources, since we'll just throw the whole event away
1298 idx
= CFArrayGetFirstIndexOfValue(__CFReadSockets
, CFRangeMake(0, CFArrayGetCount(__CFReadSockets
)), s
);
1300 CFArrayRemoveValueAtIndex(__CFReadSockets
, idx
);
1301 __CFSocketClearFDForRead(s
);
1303 #endif // !USE_V1_RUN_LOOP_SOURCE
1304 previousSocketManagerIteration
= __CFSocketManagerIteration
;
1305 __CFSpinUnlock(&__CFActiveSocketsLock
);
1307 if (wakeup
&& __CFSocketManagerThread
) {
1308 Boolean doneWaiting
= false;
1310 #if defined(LOG_CFSOCKET)
1311 fprintf(stdout
, "invalidation wants socket iteration to change from %lu\n", previousSocketManagerIteration
);
1313 send(__CFWakeupSocketPair
[0], &c
, sizeof(c
), 0);
1314 #if !defined(__WIN32__)
1315 while (!doneWaiting
) {
1316 __CFSpinLock(&__CFActiveSocketsLock
);
1317 if (previousSocketManagerIteration
!= __CFSocketManagerIteration
) doneWaiting
= true;
1318 #if defined(LOG_CFSOCKET)
1319 fprintf(stdout
, "invalidation comparing socket iteration %lu to previous %lu\n", __CFSocketManagerIteration
, previousSocketManagerIteration
);
1321 __CFSpinUnlock(&__CFActiveSocketsLock
);
1323 struct timespec ts
= {0, 1};
1324 // ??? depress priority
1325 nanosleep(&ts
, NULL
);
1331 CFDictionaryRemoveValue(__CFAllSockets
, (void *)(s
->_socket
));
1332 if ((s
->_f
.client
& kCFSocketCloseOnInvalidate
) != 0) closesocket(s
->_socket
);
1333 s
->_socket
= INVALID_SOCKET
;
1334 if (NULL
!= s
->_peerAddress
) {
1335 CFRelease(s
->_peerAddress
);
1336 s
->_peerAddress
= NULL
;
1338 #if !defined(USE_V1_RUN_LOOP_SOURCE)
1339 if (NULL
!= s
->_dataQueue
) {
1340 CFRelease(s
->_dataQueue
);
1341 s
->_dataQueue
= NULL
;
1343 if (NULL
!= s
->_addressQueue
) {
1344 CFRelease(s
->_addressQueue
);
1345 s
->_addressQueue
= NULL
;
1347 s
->_socketSetCount
= 0;
1348 #endif // !USE_V1_RUN_LOOP_SOURCE
1349 for (idx
= CFArrayGetCount(s
->_runLoops
); idx
--;) {
1350 CFRunLoopWakeUp((CFRunLoopRef
)CFArrayGetValueAtIndex(s
->_runLoops
, idx
));
1352 CFRelease(s
->_runLoops
);
1353 s
->_runLoops
= NULL
;
1354 source0
= s
->_source0
;
1356 contextInfo
= s
->_context
.info
;
1357 contextRelease
= s
->_context
.release
;
1358 s
->_context
.info
= 0;
1359 s
->_context
.retain
= 0;
1360 s
->_context
.release
= 0;
1361 s
->_context
.copyDescription
= 0;
1362 __CFSocketUnlock(s
);
1363 if (NULL
!= contextRelease
) {
1364 contextRelease(contextInfo
);
1366 if (NULL
!= source0
) {
1367 CFRunLoopSourceInvalidate(source0
);
1370 #if defined(USE_V1_RUN_LOOP_SOURCE)
1371 // Important to do the v1 source after the v0 source, since cancelling the v0 source
1372 // references the v1 source (since the v1 source is added/removed from RunLoops as a
1373 // side-effect of the v0 source being added/removed).
1374 if (NULL
!= s
->_source1
) {
1375 CFRunLoopSourceInvalidate(s
->_source1
);
1376 CFRelease(s
->_source1
);
1379 CloseHandle(s
->_event
);
1382 __CFSocketUnlock(s
);
1384 __CFSpinUnlock(&__CFAllSocketsLock
);
1388 void CFSocketInvalidate(CFSocketRef s
) {__CFSocketInvalidate(s
, true);}
1390 Boolean
CFSocketIsValid(CFSocketRef s
) {
1391 __CFGenericValidateType(s
, __kCFSocketTypeID
);
1392 return __CFSocketIsValid(s
);
1395 CFSocketNativeHandle
CFSocketGetNative(CFSocketRef s
) {
1396 __CFGenericValidateType(s
, __kCFSocketTypeID
);
1400 CFDataRef
CFSocketCopyAddress(CFSocketRef s
) {
1401 CFDataRef result
= NULL
;
1402 __CFGenericValidateType(s
, __kCFSocketTypeID
);
1404 __CFSocketEstablishAddress(s
);
1405 if (NULL
!= s
->_address
) {
1406 result
= CFRetain(s
->_address
);
1408 __CFSocketUnlock(s
);
1412 CFDataRef
CFSocketCopyPeerAddress(CFSocketRef s
) {
1413 CFDataRef result
= NULL
;
1414 __CFGenericValidateType(s
, __kCFSocketTypeID
);
1416 __CFSocketEstablishPeerAddress(s
);
1417 if (NULL
!= s
->_peerAddress
) {
1418 result
= CFRetain(s
->_peerAddress
);
1420 __CFSocketUnlock(s
);
1424 void CFSocketGetContext(CFSocketRef s
, CFSocketContext
*context
) {
1425 __CFGenericValidateType(s
, __kCFSocketTypeID
);
1426 CFAssert1(0 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__
);
1427 *context
= s
->_context
;
1430 __private_extern__
void CFSocketReschedule(CFSocketRef s
) {
1431 CFSocketEnableCallBacks(s
, __CFSocketCallBackTypes(s
));
1434 CFOptionFlags
CFSocketGetSocketFlags(CFSocketRef s
) {
1435 __CFGenericValidateType(s
, __kCFSocketTypeID
);
1436 return s
->_f
.client
;
1439 void CFSocketSetSocketFlags(CFSocketRef s
, CFOptionFlags flags
) {
1440 __CFGenericValidateType(s
, __kCFSocketTypeID
);
1442 #if defined(LOG_CFSOCKET)
1443 fprintf(stdout
, "setting flags for socket %d, from 0x%x to 0x%lx\n", s
->_socket
, s
->_f
.client
, flags
);
1445 s
->_f
.client
= flags
;
1446 __CFSocketUnlock(s
);
1449 void CFSocketDisableCallBacks(CFSocketRef s
, CFOptionFlags callBackTypes
) {
1450 Boolean wakeup
= false;
1451 uint8_t readCallBackType
;
1452 __CFGenericValidateType(s
, __kCFSocketTypeID
);
1454 if (__CFSocketIsValid(s
) && __CFSocketIsScheduled(s
)) {
1455 callBackTypes
&= __CFSocketCallBackTypes(s
);
1456 readCallBackType
= __CFSocketReadCallBackType(s
);
1457 s
->_f
.disabled
|= callBackTypes
;
1458 #if defined(LOG_CFSOCKET)
1459 fprintf(stdout
, "unscheduling socket %d with flags 0x%x disabled 0x%x connected 0x%x for types 0x%lx\n", s
->_socket
, s
->_f
.client
, s
->_f
.disabled
, s
->_f
.connected
, callBackTypes
);
1461 __CFSpinLock(&__CFActiveSocketsLock
);
1462 if ((readCallBackType
== kCFSocketAcceptCallBack
) || !__CFSocketIsConnectionOriented(s
)) s
->_f
.connected
= TRUE
;
1463 if (((callBackTypes
& kCFSocketWriteCallBack
) != 0) || (((callBackTypes
& kCFSocketConnectCallBack
) != 0) && !s
->_f
.connected
)) {
1464 if (__CFSocketClearFDForWrite(s
)) {
1465 // do not wake up the socket manager thread if all relevant write callbacks are disabled
1466 CFOptionFlags writeCallBacksAvailable
= __CFSocketCallBackTypes(s
) & (kCFSocketWriteCallBack
| kCFSocketConnectCallBack
);
1467 if (s
->_f
.connected
) writeCallBacksAvailable
&= ~kCFSocketConnectCallBack
;
1468 if ((s
->_f
.disabled
& writeCallBacksAvailable
) != writeCallBacksAvailable
) wakeup
= true;
1469 #if defined(__WIN32__)
1470 __CFSocketFdClr(s
->_socket
, __CFExceptSocketsFds
);
1474 if (readCallBackType
!= kCFSocketNoCallBack
&& (callBackTypes
& readCallBackType
) != 0) {
1475 if (__CFSocketClearFDForRead(s
)) {
1476 #if !defined(USE_V1_RUN_LOOP_SOURCE)
1477 // do not wake up the socket manager thread if callback type is read
1478 if (readCallBackType
!= kCFSocketReadCallBack
) wakeup
= true;
1482 __CFSpinUnlock(&__CFActiveSocketsLock
);
1484 __CFSocketUnlock(s
);
1485 if (wakeup
&& __CFSocketManagerThread
) {
1487 send(__CFWakeupSocketPair
[0], &c
, sizeof(c
), 0);
1491 // "force" means to clear the disabled bits set by DisableCallBacks and always reenable.
1492 // if (!force) we respect those bits, meaning they may stop us from enabling.
1493 // In addition, if !force we assume that the sockets have already been added to the
1494 // __CFReadSockets and __CFWriteSockets arrays. This is true because the callbacks start
1495 // enabled when the CFSocket is created (at which time we enable with force).
1496 // Called with SocketLock held, returns with it released!
1497 void __CFSocketEnableCallBacks(CFSocketRef s
, CFOptionFlags callBackTypes
, Boolean force
, uint8_t wakeupChar
) {
1498 Boolean wakeup
= FALSE
;
1499 if (!callBackTypes
) {
1500 __CFSocketUnlock(s
);
1503 if (__CFSocketIsValid(s
) && __CFSocketIsScheduled(s
)) {
1504 Boolean turnOnWrite
= FALSE
, turnOnConnect
= FALSE
, turnOnRead
= FALSE
;
1505 uint8_t readCallBackType
= __CFSocketReadCallBackType(s
);
1506 callBackTypes
&= __CFSocketCallBackTypes(s
);
1507 if (force
) s
->_f
.disabled
&= ~callBackTypes
;
1508 #if defined(LOG_CFSOCKET)
1509 fprintf(stdout
, "rescheduling socket %d with flags 0x%x disabled 0x%x connected 0x%x for types 0x%lx\n", s
->_socket
, s
->_f
.client
, s
->_f
.disabled
, s
->_f
.connected
, callBackTypes
);
1511 /* We will wait for connection only for connection-oriented, non-rendezvous sockets that are not already connected. Mark others as already connected. */
1512 if ((readCallBackType
== kCFSocketAcceptCallBack
) || !__CFSocketIsConnectionOriented(s
)) s
->_f
.connected
= TRUE
;
1514 // First figure out what to turn on
1515 if (s
->_f
.connected
|| (callBackTypes
& kCFSocketConnectCallBack
) == 0) {
1516 // if we want write callbacks and they're not disabled...
1517 if ((callBackTypes
& kCFSocketWriteCallBack
) != 0 && (s
->_f
.disabled
& kCFSocketWriteCallBack
) == 0) turnOnWrite
= TRUE
;
1519 // if we want connect callbacks and they're not disabled...
1520 if ((callBackTypes
& kCFSocketConnectCallBack
) != 0 && (s
->_f
.disabled
& kCFSocketConnectCallBack
) == 0) turnOnConnect
= TRUE
;
1522 // if we want read callbacks and they're not disabled...
1523 if (readCallBackType
!= kCFSocketNoCallBack
&& (callBackTypes
& readCallBackType
) != 0 && (s
->_f
.disabled
& kCFSocketReadCallBack
) == 0) turnOnRead
= TRUE
;
1525 // Now turn on the callbacks we've determined that we want on
1526 if (turnOnRead
|| turnOnWrite
|| turnOnConnect
) {
1527 __CFSpinLock(&__CFActiveSocketsLock
);
1528 #if defined(USE_V1_RUN_LOOP_SOURCE)
1531 SInt32 idx
= CFArrayGetFirstIndexOfValue(__CFWriteSockets
, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets
)), s
);
1532 if (kCFNotFound
== idx
) CFArrayAppendValue(__CFWriteSockets
, s
);
1534 // If we can tell the socket is writable, just reschedule the v1 source. Else we need
1535 // a real notification from the OS, so enable the SocketManager's listening.
1536 if (__CFSocketCanAcceptBytes(s
)) {
1537 SetEvent(s
->_event
);
1538 s
->_f
.writableHint
= TRUE
;
1540 if (__CFSocketSetFDForWrite(s
)) wakeup
= true;
1543 if (turnOnConnect
) __CFSocketSetWholeEventMask(s
, s
->_oldEventMask
| FD_CONNECT
);
1544 if (turnOnRead
) __CFSocketSetFDForRead(s
);
1545 #else // !USE_V1_RUN_LOOP_SOURCE
1546 if (turnOnWrite
|| turnOnConnect
) {
1548 SInt32 idx
= CFArrayGetFirstIndexOfValue(__CFWriteSockets
, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets
)), s
);
1549 if (kCFNotFound
== idx
) CFArrayAppendValue(__CFWriteSockets
, s
);
1551 if (__CFSocketSetFDForWrite(s
)) wakeup
= true;
1552 #if defined(__WIN32__)
1553 if ((callBackTypes
& kCFSocketConnectCallBack
) != 0 && !s
->_f
.connected
) __CFSocketFdSet(s
->_socket
, __CFExceptSocketsFds
);
1558 SInt32 idx
= CFArrayGetFirstIndexOfValue(__CFReadSockets
, CFRangeMake(0, CFArrayGetCount(__CFReadSockets
)), s
);
1559 if (kCFNotFound
== idx
) CFArrayAppendValue(__CFReadSockets
, s
);
1561 if (__CFSocketSetFDForRead(s
)) wakeup
= true;
1564 if (wakeup
&& NULL
== __CFSocketManagerThread
) __CFSocketManagerThread
= __CFStartSimpleThread(__CFSocketManager
, 0);
1565 __CFSpinUnlock(&__CFActiveSocketsLock
);
1568 __CFSocketUnlock(s
);
1569 if (wakeup
) send(__CFWakeupSocketPair
[0], &wakeupChar
, sizeof(wakeupChar
), 0);
1572 void CFSocketEnableCallBacks(CFSocketRef s
, CFOptionFlags callBackTypes
) {
1573 __CFGenericValidateType(s
, __kCFSocketTypeID
);
1575 __CFSocketEnableCallBacks(s
, callBackTypes
, TRUE
, 'r');
1578 static void __CFSocketSchedule(void *info
, CFRunLoopRef rl
, CFStringRef mode
) {
1579 CFSocketRef s
= info
;
1581 //??? also need to arrange delivery of all pending data
1582 if (__CFSocketIsValid(s
)) {
1583 CFArrayAppendValue(s
->_runLoops
, rl
);
1584 s
->_socketSetCount
++;
1585 // Since the v0 source is listened to on the SocketMgr thread, no matter how many modes it
1586 // is added to we just need to enable it there once (and _socketSetCount gives us a refCount
1587 // to know when we can finally disable it).
1588 if (1 == s
->_socketSetCount
) {
1589 #if defined(LOG_CFSOCKET)
1590 fprintf(stdout
, "scheduling socket %d\n", s
->_socket
);
1592 __CFSocketEnableCallBacks(s
, __CFSocketCallBackTypes(s
), TRUE
, 's'); // unlocks s
1594 __CFSocketUnlock(s
);
1595 #if defined(USE_V1_RUN_LOOP_SOURCE)
1596 // Since the v1 source is listened to in rl on this thread, we need to add it to all modes
1597 // the v0 source is added to.
1598 CFRunLoopAddSource(rl
, s
->_source1
, mode
);
1599 CFRunLoopWakeUp(rl
);
1602 __CFSocketUnlock(s
);
1605 static void __CFSocketCancel(void *info
, CFRunLoopRef rl
, CFStringRef mode
) {
1606 CFSocketRef s
= info
;
1609 s
->_socketSetCount
--;
1610 if (0 == s
->_socketSetCount
) {
1611 __CFSpinLock(&__CFActiveSocketsLock
);
1612 idx
= CFArrayGetFirstIndexOfValue(__CFWriteSockets
, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets
)), s
);
1614 CFArrayRemoveValueAtIndex(__CFWriteSockets
, idx
);
1615 __CFSocketClearFDForWrite(s
);
1616 #if defined(__WIN32__)
1617 __CFSocketFdClr(s
->_socket
, __CFExceptSocketsFds
);
1620 #if !defined(USE_V1_RUN_LOOP_SOURCE)
1621 idx
= CFArrayGetFirstIndexOfValue(__CFReadSockets
, CFRangeMake(0, CFArrayGetCount(__CFReadSockets
)), s
);
1623 CFArrayRemoveValueAtIndex(__CFReadSockets
, idx
);
1624 __CFSocketClearFDForRead(s
);
1627 __CFSpinUnlock(&__CFActiveSocketsLock
);
1629 #if defined(USE_V1_RUN_LOOP_SOURCE)
1630 CFRunLoopRemoveSource(rl
, s
->_source1
, mode
);
1631 CFRunLoopWakeUp(rl
);
1632 if (0 == s
->_socketSetCount
&& s
->_socket
!= INVALID_SOCKET
) {
1633 __CFSocketSetWholeEventMask(s
, FD_CLOSE
|FD_CONNECT
);
1636 if (NULL
!= s
->_runLoops
) {
1637 idx
= CFArrayGetFirstIndexOfValue(s
->_runLoops
, CFRangeMake(0, CFArrayGetCount(s
->_runLoops
)), rl
);
1638 if (0 <= idx
) CFArrayRemoveValueAtIndex(s
->_runLoops
, idx
);
1640 __CFSocketUnlock(s
);
1643 // Note: must be called with socket lock held, then returns with it released
1644 // Used by both the v0 and v1 RunLoopSource perform routines
1645 static void __CFSocketDoCallback(CFSocketRef s
, CFDataRef data
, CFDataRef address
, CFSocketNativeHandle sock
) {
1646 CFSocketCallBack callout
= NULL
;
1647 void *contextInfo
= NULL
;
1648 SInt32 errorCode
= 0;
1649 Boolean readSignalled
= false, writeSignalled
= false, connectSignalled
= false, calledOut
= false;
1650 uint8_t readCallBackType
, callBackTypes
;
1652 callBackTypes
= __CFSocketCallBackTypes(s
);
1653 readCallBackType
= __CFSocketReadCallBackType(s
);
1654 readSignalled
= __CFSocketIsReadSignalled(s
);
1655 writeSignalled
= __CFSocketIsWriteSignalled(s
);
1656 connectSignalled
= writeSignalled
&& !s
->_f
.connected
;
1657 __CFSocketUnsetReadSignalled(s
);
1658 __CFSocketUnsetWriteSignalled(s
);
1659 callout
= s
->_callout
;
1660 contextInfo
= s
->_context
.info
;
1661 #if defined(LOG_CFSOCKET)
1662 fprintf(stdout
, "entering perform for socket %d with read signalled %d write signalled %d connect signalled %d callback types %d\n", s
->_socket
, readSignalled
, writeSignalled
, connectSignalled
, callBackTypes
);
1664 if (writeSignalled
) {
1665 errorCode
= s
->_errorCode
;
1666 s
->_f
.connected
= TRUE
;
1668 __CFSocketUnlock(s
);
1669 if ((callBackTypes
& kCFSocketConnectCallBack
) != 0) {
1670 if (connectSignalled
&& (!calledOut
|| CFSocketIsValid(s
))) {
1672 #if defined(LOG_CFSOCKET)
1673 fprintf(stdout
, "perform calling out error %ld to socket %d\n", errorCode
, s
->_socket
);
1675 if (callout
) callout(s
, kCFSocketConnectCallBack
, NULL
, &errorCode
, contextInfo
);
1678 #if defined(LOG_CFSOCKET)
1679 fprintf(stdout
, "perform calling out connect to socket %d\n", s
->_socket
);
1681 if (callout
) callout(s
, kCFSocketConnectCallBack
, NULL
, NULL
, contextInfo
);
1686 if (kCFSocketDataCallBack
== readCallBackType
) {
1687 if (NULL
!= data
&& (!calledOut
|| CFSocketIsValid(s
))) {
1688 SInt32 datalen
= CFDataGetLength(data
);
1689 #if defined(LOG_CFSOCKET)
1690 fprintf(stdout
, "perform calling out data of length %ld to socket %d\n", datalen
, s
->_socket
);
1692 if (callout
) callout(s
, kCFSocketDataCallBack
, address
, data
, contextInfo
);
1694 if (0 == datalen
) __CFSocketInvalidate(s
, true);
1696 } else if (kCFSocketAcceptCallBack
== readCallBackType
) {
1697 if (INVALID_SOCKET
!= sock
&& (!calledOut
|| CFSocketIsValid(s
))) {
1698 #if defined(LOG_CFSOCKET)
1699 fprintf(stdout
, "perform calling out accept of socket %d to socket %d\n", sock
, s
->_socket
);
1701 if (callout
) callout(s
, kCFSocketAcceptCallBack
, address
, &sock
, contextInfo
);
1704 } else if (kCFSocketReadCallBack
== readCallBackType
) {
1705 if (readSignalled
&& (!calledOut
|| CFSocketIsValid(s
))) {
1706 #if defined(LOG_CFSOCKET)
1707 fprintf(stdout
, "perform calling out read to socket %d\n", s
->_socket
);
1709 if (callout
) callout(s
, kCFSocketReadCallBack
, NULL
, NULL
, contextInfo
);
1713 if ((callBackTypes
& kCFSocketWriteCallBack
) != 0) {
1714 if (writeSignalled
&& !errorCode
&& (!calledOut
|| CFSocketIsValid(s
))) {
1715 #if defined(LOG_CFSOCKET)
1716 fprintf(stdout
, "perform calling out write to socket %d\n", s
->_socket
);
1718 if (callout
) callout(s
, kCFSocketWriteCallBack
, NULL
, NULL
, contextInfo
);
1724 #if defined(USE_V1_RUN_LOOP_SOURCE)
1725 static HANDLE
__CFSocketGetPort(void *info
) {
1726 CFSocketRef s
= info
;
1730 static void __CFSocketPerformV1(void *info
) {
1731 CFSocketRef s
= info
;
1732 WSANETWORKEVENTS eventsTranspired
;
1733 uint8_t readCallBackType
= __CFSocketReadCallBackType(s
);
1734 CFOptionFlags callBacksSignalled
= 0;
1736 int err
= WSAEnumNetworkEvents(s
->_socket
, s
->_event
, &eventsTranspired
);
1737 CFAssert2(0 == err
, __kCFLogAssertion
, "%s(): WSAEnumNetworkEvents failed: %d", __PRETTY_FUNCTION__
, WSAGetLastError());
1738 #if defined(LOG_CFSOCKET)
1739 fprintf(stdout
, "socket %d with flags 0x%x disabled 0x%x connected 0x%x received NetworkEvents 0x%lx\n", s
->_socket
, s
->_f
.client
, s
->_f
.disabled
, s
->_f
.connected
, eventsTranspired
.lNetworkEvents
);
1741 // Get these bits cleared before any callouts, just as the SocketMgr thread used to
1742 if (eventsTranspired
.lNetworkEvents
& FD_READ
) {
1743 __CFSpinLock(&__CFActiveSocketsLock
);
1744 __CFSocketClearFDForRead(s
);
1745 __CFSpinUnlock(&__CFActiveSocketsLock
);
1748 if (eventsTranspired
.lNetworkEvents
& FD_READ
|| eventsTranspired
.lNetworkEvents
& FD_ACCEPT
) callBacksSignalled
|= readCallBackType
;
1749 if (eventsTranspired
.lNetworkEvents
& FD_CONNECT
|| s
->_f
.writableHint
) callBacksSignalled
|= kCFSocketWriteCallBack
;
1750 s
->_f
.writableHint
= FALSE
;
1751 CFAssert2(0 == (eventsTranspired
.lNetworkEvents
& FD_WRITE
), __kCFLogAssertion
, "%s(): WSAEnumNetworkEvents returned unexpected events: %lx", __PRETTY_FUNCTION__
, eventsTranspired
.lNetworkEvents
);
1753 #if defined(LOG_CFSOCKET)
1754 // I believe all these errors will be re-found in __CFSocketHandleRead and __CFSocketHandleWrite
1755 // so we don't need to check for them here.
1756 if (eventsTranspired
.lNetworkEvents
& FD_READ
&& eventsTranspired
.iErrorCode
[FD_READ_BIT
] != 0)
1757 fprintf(stdout
, "socket %d has error %d for FD_READ\n", s
->_socket
, eventsTranspired
.iErrorCode
[FD_READ_BIT
]);
1758 if (eventsTranspired
.lNetworkEvents
& FD_WRITE
&& eventsTranspired
.iErrorCode
[FD_WRITE_BIT
] != 0)
1759 fprintf(stdout
, "socket %d has error %d for FD_WRITE\n", s
->_socket
, eventsTranspired
.iErrorCode
[FD_WRITE_BIT
]);
1760 if (eventsTranspired
.lNetworkEvents
& FD_CLOSE
&& eventsTranspired
.iErrorCode
[FD_CLOSE_BIT
] != 0)
1761 fprintf(stdout
, "socket %d has error %d for FD_CLOSE\n", s
->_socket
, eventsTranspired
.iErrorCode
[FD_CLOSE_BIT
]);
1762 if (eventsTranspired
.lNetworkEvents
& FD_CONNECT
&& eventsTranspired
.iErrorCode
[FD_CONNECT_BIT
] != 0)
1763 fprintf(stdout
, "socket %d has error %d for FD_CONNECT\n", s
->_socket
, eventsTranspired
.iErrorCode
[FD_CONNECT_BIT
]);
1766 if (0 != (eventsTranspired
.lNetworkEvents
& FD_CLOSE
)) s
->_f
.closeSignaled
= TRUE
;
1767 if (0 != (callBacksSignalled
& readCallBackType
)) __CFSocketHandleRead(s
);
1768 if (0 != (callBacksSignalled
& kCFSocketWriteCallBack
)) __CFSocketHandleWrite(s
, TRUE
);
1769 // FD_CLOSE is edge triggered (sent once). FD_READ is level triggered (sent as long as there are
1770 // bytes). Event after we get FD_CLOSE, if there are still bytes to be read we'll keep getting
1771 // FD_READ until the pipe is drained. However, an EOF condition on the socket will -not-
1772 // trigger an FD_READ, so we must be careful not to stall out after the last bytes are read.
1773 // Finally, a client may have already noticed the EOF in the Read callout just done, so we don't
1774 // call him again if the socket has been invalidated.
1775 // All this implies that once we have seen FD_CLOSE, we need to keep checking for EOF on the read
1776 // side to give the client one last callback for that case.
1777 if (__CFSocketIsValid(s
) && (eventsTranspired
.lNetworkEvents
== FD_CLOSE
|| (s
->_f
.closeSignaled
&& !__CFSocketHasBytesToRead(s
)))) {
1778 if (readCallBackType
!= kCFSocketNoCallBack
) {
1779 __CFSocketHandleRead(s
);
1780 } else if ((__CFSocketCallBackTypes(s
) & kCFSocketWriteCallBack
) != 0) {
1781 __CFSocketHandleWrite(s
, TRUE
);
1785 // Only reenable callbacks that are auto-reenabled
1787 __CFSocketEnableCallBacks(s
, callBacksSignalled
& s
->_f
.client
, FALSE
, 'P'); // unlocks s
1789 #endif // USE_V1_RUN_LOOP_SOURCE
1791 static void __CFSocketPerformV0(void *info
) {
1792 CFSocketRef s
= info
;
1793 CFDataRef data
= NULL
;
1794 CFDataRef address
= NULL
;
1795 CFSocketNativeHandle sock
= INVALID_SOCKET
;
1796 uint8_t readCallBackType
, callBackTypes
;
1797 CFRunLoopRef rl
= NULL
;
1800 if (!__CFSocketIsValid(s
)) {
1801 __CFSocketUnlock(s
);
1804 callBackTypes
= __CFSocketCallBackTypes(s
);
1805 readCallBackType
= __CFSocketReadCallBackType(s
);
1806 CFOptionFlags callBacksSignalled
= 0;
1807 if (__CFSocketIsReadSignalled(s
)) callBacksSignalled
|= readCallBackType
;
1808 if (__CFSocketIsWriteSignalled(s
)) callBacksSignalled
|= kCFSocketWriteCallBack
;
1810 #if !defined(USE_V1_RUN_LOOP_SOURCE)
1811 if (kCFSocketDataCallBack
== readCallBackType
) {
1812 if (NULL
!= s
->_dataQueue
&& 0 < CFArrayGetCount(s
->_dataQueue
)) {
1813 data
= CFArrayGetValueAtIndex(s
->_dataQueue
, 0);
1815 CFArrayRemoveValueAtIndex(s
->_dataQueue
, 0);
1816 address
= CFArrayGetValueAtIndex(s
->_addressQueue
, 0);
1818 CFArrayRemoveValueAtIndex(s
->_addressQueue
, 0);
1820 } else if (kCFSocketAcceptCallBack
== readCallBackType
) {
1821 if (NULL
!= s
->_dataQueue
&& 0 < CFArrayGetCount(s
->_dataQueue
)) {
1822 sock
= (CFSocketNativeHandle
)CFArrayGetValueAtIndex(s
->_dataQueue
, 0);
1823 CFArrayRemoveValueAtIndex(s
->_dataQueue
, 0);
1824 address
= CFArrayGetValueAtIndex(s
->_addressQueue
, 0);
1826 CFArrayRemoveValueAtIndex(s
->_addressQueue
, 0);
1831 __CFSocketDoCallback(s
, data
, address
, sock
); // does __CFSocketUnlock(s)
1832 if (NULL
!= data
) CFRelease(data
);
1833 if (NULL
!= address
) CFRelease(address
);
1836 #if !defined(USE_V1_RUN_LOOP_SOURCE)
1837 if (__CFSocketIsValid(s
) && kCFSocketNoCallBack
!= readCallBackType
) {
1838 // if there's still more data, we want to wake back up right away
1839 if ((kCFSocketDataCallBack
== readCallBackType
|| kCFSocketAcceptCallBack
== readCallBackType
) && NULL
!= s
->_dataQueue
&& 0 < CFArrayGetCount(s
->_dataQueue
)) {
1840 CFRunLoopSourceSignal(s
->_source0
);
1841 #if defined(LOG_CFSOCKET)
1842 fprintf(stdout
, "perform short-circuit signaling source for socket %d with flags 0x%x disabled 0x%x connected 0x%x\n", s
->_socket
, s
->_f
.client
, s
->_f
.disabled
, s
->_f
.connected
);
1844 rl
= __CFSocketCopyRunLoopToWakeUp(s
);
1848 // Only reenable callbacks that are auto-reenabled
1849 __CFSocketEnableCallBacks(s
, callBacksSignalled
& s
->_f
.client
, FALSE
, 'p'); // unlocks s
1852 CFRunLoopWakeUp(rl
);
1857 CFRunLoopSourceRef
CFSocketCreateRunLoopSource(CFAllocatorRef allocator
, CFSocketRef s
, CFIndex order
) {
1858 CFRunLoopSourceRef result
= NULL
;
1859 __CFGenericValidateType(s
, __kCFSocketTypeID
);
1861 if (__CFSocketIsValid(s
)) {
1862 if (NULL
== s
->_source0
) {
1863 CFRunLoopSourceContext context
;
1864 #if defined(USE_V1_RUN_LOOP_SOURCE)
1865 CFRunLoopSourceContext1 context1
;
1866 context1
.version
= 1;
1868 context1
.retain
= CFRetain
;
1869 context1
.release
= CFRelease
;
1870 context1
.copyDescription
= CFCopyDescription
;
1871 context1
.equal
= CFEqual
;
1872 context1
.hash
= CFHash
;
1873 context1
.getPort
= __CFSocketGetPort
;
1874 context1
.perform
= __CFSocketPerformV1
;
1875 s
->_source1
= CFRunLoopSourceCreate(allocator
, order
, (CFRunLoopSourceContext
*)&context1
);
1877 context
.version
= 0;
1879 context
.retain
= CFRetain
;
1880 context
.release
= CFRelease
;
1881 context
.copyDescription
= CFCopyDescription
;
1882 context
.equal
= CFEqual
;
1883 context
.hash
= CFHash
;
1884 context
.schedule
= __CFSocketSchedule
;
1885 context
.cancel
= __CFSocketCancel
;
1886 context
.perform
= __CFSocketPerformV0
;
1887 s
->_source0
= CFRunLoopSourceCreate(allocator
, order
, &context
);
1889 CFRetain(s
->_source0
); /* This retain is for the receiver */
1890 result
= s
->_source0
;
1892 __CFSocketUnlock(s
);
1896 //??? need timeout, error handling, retries
1897 CFSocketError
CFSocketSendData(CFSocketRef s
, CFDataRef address
, CFDataRef data
, CFTimeInterval timeout
) {
1898 const uint8_t *dataptr
, *addrptr
= NULL
;
1899 SInt32 datalen
, addrlen
= 0, size
= 0;
1900 CFSocketNativeHandle sock
= INVALID_SOCKET
;
1902 __CFGenericValidateType(s
, __kCFSocketTypeID
);
1904 addrptr
= CFDataGetBytePtr(address
);
1905 addrlen
= CFDataGetLength(address
);
1907 dataptr
= CFDataGetBytePtr(data
);
1908 datalen
= CFDataGetLength(data
);
1910 if (__CFSocketIsValid(s
)) sock
= s
->_socket
;
1911 __CFSocketUnlock(s
);
1912 if (INVALID_SOCKET
!= sock
) {
1914 __CFSocketWriteLock(s
);
1915 tv
.tv_sec
= (0 >= timeout
|| INT_MAX
<= timeout
) ? INT_MAX
: (int)(float)floor(timeout
);
1916 tv
.tv_usec
= (int)((timeout
- floor(timeout
)) * 1.0E6
);
1917 setsockopt(sock
, SOL_SOCKET
, SO_SNDTIMEO
, (void *)&tv
, sizeof(tv
)); // cast for WinSock bad API
1918 if (NULL
!= addrptr
&& 0 < addrlen
) {
1919 size
= sendto(sock
, dataptr
, datalen
, 0, (struct sockaddr
*)addrptr
, addrlen
);
1921 size
= send(sock
, dataptr
, datalen
, 0);
1923 #if defined(LOG_CFSOCKET)
1924 fprintf(stdout
, "wrote %ld bytes to socket %d\n", size
, s
->_socket
);
1926 __CFSocketWriteUnlock(s
);
1929 return (size
> 0) ? kCFSocketSuccess
: kCFSocketError
;
1933 CFSocketError
*error
;
1934 CFPropertyListRef
*value
;
1936 } __CFSocketNameRegistryResponse
;
1938 static void __CFSocketHandleNameRegistryReply(CFSocketRef s
, CFSocketCallBackType type
, CFDataRef address
, const void *data
, void *info
) {
1939 CFDataRef replyData
= (CFDataRef
)data
;
1940 __CFSocketNameRegistryResponse
*response
= (__CFSocketNameRegistryResponse
*)info
;
1941 CFDictionaryRef replyDictionary
= NULL
;
1942 CFPropertyListRef value
;
1943 replyDictionary
= CFPropertyListCreateFromXMLData(NULL
, replyData
, kCFPropertyListImmutable
, NULL
);
1944 if (NULL
!= response
->error
) *(response
->error
) = kCFSocketError
;
1945 if (NULL
!= replyDictionary
) {
1946 if (CFGetTypeID((CFTypeRef
)replyDictionary
) == CFDictionaryGetTypeID() && NULL
!= (value
= CFDictionaryGetValue(replyDictionary
, kCFSocketResultKey
))) {
1947 if (NULL
!= response
->error
) *(response
->error
) = kCFSocketSuccess
;
1948 if (NULL
!= response
->value
) *(response
->value
) = CFRetain(value
);
1949 if (NULL
!= response
->address
) *(response
->address
) = address
? CFDataCreateCopy(NULL
, address
) : NULL
;
1951 CFRelease(replyDictionary
);
1953 CFSocketInvalidate(s
);
1956 static void __CFSocketSendNameRegistryRequest(CFSocketSignature
*signature
, CFDictionaryRef requestDictionary
, __CFSocketNameRegistryResponse
*response
, CFTimeInterval timeout
) {
1957 CFDataRef requestData
= NULL
;
1958 CFSocketContext context
= {0, response
, NULL
, NULL
, NULL
};
1959 CFSocketRef s
= NULL
;
1960 CFRunLoopSourceRef source
= NULL
;
1961 if (NULL
!= response
->error
) *(response
->error
) = kCFSocketError
;
1962 requestData
= CFPropertyListCreateXMLData(NULL
, requestDictionary
);
1963 if (NULL
!= requestData
) {
1964 if (NULL
!= response
->error
) *(response
->error
) = kCFSocketTimeout
;
1965 s
= CFSocketCreateConnectedToSocketSignature(NULL
, signature
, kCFSocketDataCallBack
, __CFSocketHandleNameRegistryReply
, &context
, timeout
);
1967 if (kCFSocketSuccess
== CFSocketSendData(s
, NULL
, requestData
, timeout
)) {
1968 source
= CFSocketCreateRunLoopSource(NULL
, s
, 0);
1969 CFRunLoopAddSource(CFRunLoopGetCurrent(), source
, __kCFSocketRegistryRequestRunLoopMode
);
1970 CFRunLoopRunInMode(__kCFSocketRegistryRequestRunLoopMode
, timeout
, false);
1973 CFSocketInvalidate(s
);
1976 CFRelease(requestData
);
1980 static void __CFSocketValidateSignature(const CFSocketSignature
*providedSignature
, CFSocketSignature
*signature
, uint16_t defaultPortNumber
) {
1981 struct sockaddr_in sain
, *sainp
;
1982 memset(&sain
, 0, sizeof(sain
));
1983 #if !defined(__WIN32__)
1984 sain
.sin_len
= sizeof(sain
);
1986 sain
.sin_family
= AF_INET
;
1987 sain
.sin_port
= htons(__CFSocketDefaultNameRegistryPortNumber
);
1988 sain
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
1989 if (NULL
== providedSignature
) {
1990 signature
->protocolFamily
= PF_INET
;
1991 signature
->socketType
= SOCK_STREAM
;
1992 signature
->protocol
= IPPROTO_TCP
;
1993 signature
->address
= CFDataCreate(NULL
, (uint8_t *)&sain
, sizeof(sain
));
1995 signature
->protocolFamily
= providedSignature
->protocolFamily
;
1996 signature
->socketType
= providedSignature
->socketType
;
1997 signature
->protocol
= providedSignature
->protocol
;
1998 if (0 >= signature
->protocolFamily
) signature
->protocolFamily
= PF_INET
;
1999 if (PF_INET
== signature
->protocolFamily
) {
2000 if (0 >= signature
->socketType
) signature
->socketType
= SOCK_STREAM
;
2001 if (0 >= signature
->protocol
&& SOCK_STREAM
== signature
->socketType
) signature
->protocol
= IPPROTO_TCP
;
2002 if (0 >= signature
->protocol
&& SOCK_DGRAM
== signature
->socketType
) signature
->protocol
= IPPROTO_UDP
;
2004 if (NULL
== providedSignature
->address
) {
2005 signature
->address
= CFDataCreate(NULL
, (uint8_t *)&sain
, sizeof(sain
));
2007 sainp
= (struct sockaddr_in
*)CFDataGetBytePtr(providedSignature
->address
);
2008 if ((int)sizeof(struct sockaddr_in
) <= CFDataGetLength(providedSignature
->address
) && (AF_INET
== sainp
->sin_family
|| 0 == sainp
->sin_family
)) {
2009 #if !defined(__WIN32__)
2010 sain
.sin_len
= sizeof(sain
);
2012 sain
.sin_family
= AF_INET
;
2013 sain
.sin_port
= sainp
->sin_port
;
2014 if (0 == sain
.sin_port
) sain
.sin_port
= htons(defaultPortNumber
);
2015 sain
.sin_addr
.s_addr
= sainp
->sin_addr
.s_addr
;
2016 if (htonl(INADDR_ANY
) == sain
.sin_addr
.s_addr
) sain
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
2017 signature
->address
= CFDataCreate(NULL
, (uint8_t *)&sain
, sizeof(sain
));
2019 signature
->address
= CFRetain(providedSignature
->address
);
2025 CFSocketError
CFSocketRegisterValue(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
, CFPropertyListRef value
) {
2026 CFSocketSignature signature
;
2027 CFMutableDictionaryRef dictionary
= CFDictionaryCreateMutable(NULL
, 3, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2028 CFSocketError retval
= kCFSocketError
;
2029 __CFSocketNameRegistryResponse response
= {&retval
, NULL
, NULL
};
2030 CFDictionaryAddValue(dictionary
, kCFSocketCommandKey
, kCFSocketRegisterCommand
);
2031 CFDictionaryAddValue(dictionary
, kCFSocketNameKey
, name
);
2032 if (NULL
!= value
) CFDictionaryAddValue(dictionary
, kCFSocketValueKey
, value
);
2033 __CFSocketValidateSignature(nameServerSignature
, &signature
, __CFSocketDefaultNameRegistryPortNumber
);
2034 __CFSocketSendNameRegistryRequest(&signature
, dictionary
, &response
, timeout
);
2035 CFRelease(dictionary
);
2036 CFRelease(signature
.address
);
2040 CFSocketError
CFSocketCopyRegisteredValue(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
, CFPropertyListRef
*value
, CFDataRef
*serverAddress
) {
2041 CFSocketSignature signature
;
2042 CFMutableDictionaryRef dictionary
= CFDictionaryCreateMutable(NULL
, 2, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2043 CFSocketError retval
= kCFSocketError
;
2044 __CFSocketNameRegistryResponse response
= {&retval
, value
, serverAddress
};
2045 CFDictionaryAddValue(dictionary
, kCFSocketCommandKey
, kCFSocketRetrieveCommand
);
2046 CFDictionaryAddValue(dictionary
, kCFSocketNameKey
, name
);
2047 __CFSocketValidateSignature(nameServerSignature
, &signature
, __CFSocketDefaultNameRegistryPortNumber
);
2048 __CFSocketSendNameRegistryRequest(&signature
, dictionary
, &response
, timeout
);
2049 CFRelease(dictionary
);
2050 CFRelease(signature
.address
);
2054 CFSocketError
CFSocketRegisterSocketSignature(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
, const CFSocketSignature
*signature
) {
2055 CFSocketSignature validatedSignature
;
2056 CFMutableDataRef data
= NULL
;
2057 CFSocketError retval
;
2060 if (NULL
== signature
) {
2061 retval
= CFSocketUnregister(nameServerSignature
, timeout
, name
);
2063 __CFSocketValidateSignature(signature
, &validatedSignature
, 0);
2064 if (NULL
== validatedSignature
.address
|| 0 > validatedSignature
.protocolFamily
|| 255 < validatedSignature
.protocolFamily
|| 0 > validatedSignature
.socketType
|| 255 < validatedSignature
.socketType
|| 0 > validatedSignature
.protocol
|| 255 < validatedSignature
.protocol
|| 0 >= (length
= CFDataGetLength(validatedSignature
.address
)) || 255 < length
) {
2065 retval
= kCFSocketError
;
2067 data
= CFDataCreateMutable(NULL
, sizeof(bytes
) + length
);
2068 bytes
[0] = validatedSignature
.protocolFamily
;
2069 bytes
[1] = validatedSignature
.socketType
;
2070 bytes
[2] = validatedSignature
.protocol
;
2072 CFDataAppendBytes(data
, bytes
, sizeof(bytes
));
2073 CFDataAppendBytes(data
, CFDataGetBytePtr(validatedSignature
.address
), length
);
2074 retval
= CFSocketRegisterValue(nameServerSignature
, timeout
, name
, data
);
2077 CFRelease(validatedSignature
.address
);
2082 CFSocketError
CFSocketCopyRegisteredSocketSignature(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
, CFSocketSignature
*signature
, CFDataRef
*nameServerAddress
) {
2083 CFDataRef data
= NULL
;
2084 CFSocketSignature returnedSignature
;
2085 const uint8_t *ptr
= NULL
, *aptr
= NULL
;
2088 CFDataRef serverAddress
= NULL
;
2089 CFSocketError retval
= CFSocketCopyRegisteredValue(nameServerSignature
, timeout
, name
, (CFPropertyListRef
*)&data
, &serverAddress
);
2090 if (NULL
== data
|| CFGetTypeID(data
) != CFDataGetTypeID() || NULL
== (ptr
= CFDataGetBytePtr(data
)) || (length
= CFDataGetLength(data
)) < 4) retval
= kCFSocketError
;
2091 if (kCFSocketSuccess
== retval
&& NULL
!= signature
) {
2092 returnedSignature
.protocolFamily
= (SInt32
)*ptr
++;
2093 returnedSignature
.socketType
= (SInt32
)*ptr
++;
2094 returnedSignature
.protocol
= (SInt32
)*ptr
++;
2096 returnedSignature
.address
= CFDataCreate(NULL
, ptr
, length
- 4);
2097 __CFSocketValidateSignature(&returnedSignature
, signature
, 0);
2098 CFRelease(returnedSignature
.address
);
2099 ptr
= CFDataGetBytePtr(signature
->address
);
2100 if (CFDataGetLength(signature
->address
) >= (int)sizeof(struct sockaddr_in
) && AF_INET
== ((struct sockaddr
*)ptr
)->sa_family
&& NULL
!= serverAddress
&& CFDataGetLength(serverAddress
) >= (int)sizeof(struct sockaddr_in
) && NULL
!= (aptr
= CFDataGetBytePtr(serverAddress
)) && AF_INET
== ((struct sockaddr
*)aptr
)->sa_family
) {
2101 CFMutableDataRef address
= CFDataCreateMutableCopy(NULL
, CFDataGetLength(signature
->address
), signature
->address
);
2102 mptr
= CFDataGetMutableBytePtr(address
);
2103 ((struct sockaddr_in
*)mptr
)->sin_addr
= ((struct sockaddr_in
*)aptr
)->sin_addr
;
2104 CFRelease(signature
->address
);
2105 signature
->address
= address
;
2107 if (NULL
!= nameServerAddress
) *nameServerAddress
= serverAddress
? CFRetain(serverAddress
) : NULL
;
2109 if (NULL
!= data
) CFRelease(data
);
2110 if (NULL
!= serverAddress
) CFRelease(serverAddress
);
2114 CFSocketError
CFSocketUnregister(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
) {
2115 return CFSocketRegisterValue(nameServerSignature
, timeout
, name
, NULL
);
2118 CF_EXPORT
void CFSocketSetDefaultNameRegistryPortNumber(uint16_t port
) {
2119 __CFSocketDefaultNameRegistryPortNumber
= port
;
2122 CF_EXPORT
uint16_t CFSocketGetDefaultNameRegistryPortNumber(void) {
2123 return __CFSocketDefaultNameRegistryPortNumber
;