2 * Copyright (c) 2008 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@
24 Copyright (c) 1999-2007 Apple Inc. All rights reserved.
25 Responsibility: Doug Davidson
28 #define _DARWIN_UNLIMITED_SELECT 1
30 #include <CoreFoundation/CFSocket.h>
31 #include <sys/types.h>
34 #include <CoreFoundation/CFArray.h>
35 #include <CoreFoundation/CFData.h>
36 #include <CoreFoundation/CFDictionary.h>
37 #include <CoreFoundation/CFRunLoop.h>
38 #include <CoreFoundation/CFString.h>
39 #include <CoreFoundation/CFPropertyList.h>
40 #include "CFInternal.h"
43 #include "auto_stubs.h"
45 // On Mach we use a v0 RunLoopSource to make client callbacks. That source is signalled by a
46 // separate SocketManager thread who uses select() to watch the sockets' fds.
48 //#define LOG_CFSOCKET
50 #define INVALID_SOCKET (CFSocketNativeHandle)(-1)
53 kCFSocketLeaveErrors
= 64 // candidate for publicization in future
56 static uint16_t __CFSocketDefaultNameRegistryPortNumber
= 2454;
58 CONST_STRING_DECL(kCFSocketCommandKey
, "Command")
59 CONST_STRING_DECL(kCFSocketNameKey
, "Name")
60 CONST_STRING_DECL(kCFSocketValueKey
, "Value")
61 CONST_STRING_DECL(kCFSocketResultKey
, "Result")
62 CONST_STRING_DECL(kCFSocketErrorKey
, "Error")
63 CONST_STRING_DECL(kCFSocketRegisterCommand
, "Register")
64 CONST_STRING_DECL(kCFSocketRetrieveCommand
, "Retrieve")
65 CONST_STRING_DECL(__kCFSocketRegistryRequestRunLoopMode
, "CFSocketRegistryRequest")
67 #define closesocket(a) close((a))
68 #define ioctlsocket(a,b,c) ioctl((a),(b),(c))
70 CF_INLINE
int __CFSocketLastError(void) {
71 return thread_errno();
74 CF_INLINE CFIndex
__CFSocketFdGetSize(CFDataRef fdSet
) {
75 return NBBY
* CFDataGetLength(fdSet
);
78 CF_INLINE Boolean
__CFSocketFdSet(CFSocketNativeHandle sock
, CFMutableDataRef fdSet
) {
79 /* returns true if a change occurred, false otherwise */
80 Boolean retval
= false;
81 if (INVALID_SOCKET
!= sock
&& 0 <= sock
) {
82 CFIndex numFds
= NBBY
* CFDataGetLength(fdSet
);
85 CFIndex oldSize
= numFds
/ NFDBITS
, newSize
= (sock
+ NFDBITS
) / NFDBITS
, changeInBytes
= (newSize
- oldSize
) * sizeof(fd_mask
);
86 CFDataIncreaseLength(fdSet
, changeInBytes
);
87 fds_bits
= (fd_mask
*)CFDataGetMutableBytePtr(fdSet
);
88 memset(fds_bits
+ oldSize
, 0, changeInBytes
);
90 fds_bits
= (fd_mask
*)CFDataGetMutableBytePtr(fdSet
);
92 if (!FD_ISSET(sock
, (fd_set
*)fds_bits
)) {
94 FD_SET(sock
, (fd_set
*)fds_bits
);
104 __private_extern__
void __CFSocketInitialize(void) {}
108 #define MAX_SOCKADDR_LEN 256
109 #define MAX_DATA_SIZE 65535
110 #define MAX_CONNECTION_ORIENTED_DATA_SIZE 32768
112 /* locks are to be acquired in the following order:
113 (1) __CFAllSocketsLock
114 (2) an individual CFSocket's lock
115 (3) __CFActiveSocketsLock
117 static CFSpinLock_t __CFAllSocketsLock
= CFSpinLockInit
; /* controls __CFAllSockets */
118 static CFMutableDictionaryRef __CFAllSockets
= NULL
;
119 static CFSpinLock_t __CFActiveSocketsLock
= CFSpinLockInit
; /* controls __CFRead/WriteSockets, __CFRead/WriteSocketsFds, __CFSocketManagerThread, and __CFSocketManagerIteration */
120 static volatile UInt32 __CFSocketManagerIteration
= 0;
121 static CFMutableArrayRef __CFWriteSockets
= NULL
;
122 static CFMutableArrayRef __CFReadSockets
= NULL
;
123 static CFMutableDataRef __CFWriteSocketsFds
= NULL
;
124 static CFMutableDataRef __CFReadSocketsFds
= NULL
;
125 static CFDataRef zeroLengthData
= NULL
;
126 static Boolean __CFReadSocketsTimeoutInvalid
= true; /* rebuild the timeout value before calling select */
128 static CFSocketNativeHandle __CFWakeupSocketPair
[2] = {INVALID_SOCKET
, INVALID_SOCKET
};
129 static void *__CFSocketManagerThread
= NULL
;
131 static CFTypeID __kCFSocketTypeID
= _kCFRuntimeNotATypeID
;
132 static void __CFSocketDoCallback(CFSocketRef s
, CFDataRef data
, CFDataRef address
, CFSocketNativeHandle sock
);
137 unsigned client
:8; // flags set by client (reenable, CloseOnInvalidate)
138 unsigned disabled
:8; // flags marking disabled callbacks
139 unsigned connected
:1; // Are we connected yet? (also true for connectionless sockets)
140 unsigned writableHint
:1; // Did the polling the socket show it to be writable?
141 unsigned closeSignaled
:1; // Have we seen FD_CLOSE? (only used on Win32)
145 CFSpinLock_t _writeLock
;
146 CFSocketNativeHandle _socket
; /* immutable */
150 CFDataRef _peerAddress
;
151 SInt32 _socketSetCount
;
152 CFRunLoopSourceRef _source0
; // v0 RLS, messaged from SocketMgr
153 CFMutableArrayRef _runLoops
;
154 CFSocketCallBack _callout
; /* immutable */
155 CFSocketContext _context
; /* immutable */
156 CFMutableArrayRef _dataQueue
; // queues to pass data from SocketMgr thread
157 CFMutableArrayRef _addressQueue
;
159 struct timeval _readBufferTimeout
;
160 CFMutableDataRef _readBuffer
;
161 CFIndex _bytesToBuffer
; /* is length of _readBuffer */
162 CFIndex _bytesToBufferPos
; /* where the next _CFSocketRead starts from */
163 CFIndex _bytesToBufferReadPos
; /* Where the buffer will next be read into (always after _bytesToBufferPos, but less than _bytesToBuffer) */
165 int _bufferedReadError
;
167 CFMutableDataRef _leftoverBytes
;
170 /* Bit 6 in the base reserved bits is used for write-signalled state (mutable) */
171 /* Bit 5 in the base reserved bits is used for read-signalled state (mutable) */
172 /* Bit 4 in the base reserved bits is used for invalid state (mutable) */
173 /* Bits 0-3 in the base reserved bits are used for callback types (immutable) */
174 /* Of this, bits 0-1 are used for the read callback type. */
176 CF_INLINE Boolean
__CFSocketIsWriteSignalled(CFSocketRef s
) {
177 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 6, 6);
180 CF_INLINE
void __CFSocketSetWriteSignalled(CFSocketRef s
) {
181 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 6, 6, 1);
184 CF_INLINE
void __CFSocketUnsetWriteSignalled(CFSocketRef s
) {
185 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 6, 6, 0);
188 CF_INLINE Boolean
__CFSocketIsReadSignalled(CFSocketRef s
) {
189 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 5, 5);
192 CF_INLINE
void __CFSocketSetReadSignalled(CFSocketRef s
) {
193 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 5, 5, 1);
196 CF_INLINE
void __CFSocketUnsetReadSignalled(CFSocketRef s
) {
197 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 5, 5, 0);
200 CF_INLINE Boolean
__CFSocketIsValid(CFSocketRef s
) {
201 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 4, 4);
204 CF_INLINE
void __CFSocketSetValid(CFSocketRef s
) {
205 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 4, 4, 1);
208 CF_INLINE
void __CFSocketUnsetValid(CFSocketRef s
) {
209 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 4, 4, 0);
212 CF_INLINE
uint8_t __CFSocketCallBackTypes(CFSocketRef s
) {
213 return (uint8_t)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 3, 0);
216 CF_INLINE
uint8_t __CFSocketReadCallBackType(CFSocketRef s
) {
217 return (uint8_t)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 1, 0);
220 CF_INLINE
void __CFSocketSetCallBackTypes(CFSocketRef s
, uint8_t types
) {
221 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 3, 0, types
& 0xF);
224 CF_INLINE
void __CFSocketLock(CFSocketRef s
) {
225 __CFSpinLock(&(s
->_lock
));
228 CF_INLINE
void __CFSocketUnlock(CFSocketRef s
) {
229 __CFSpinUnlock(&(s
->_lock
));
232 CF_INLINE Boolean
__CFSocketIsConnectionOriented(CFSocketRef s
) {
233 return (SOCK_STREAM
== s
->_socketType
|| SOCK_SEQPACKET
== s
->_socketType
);
236 CF_INLINE Boolean
__CFSocketIsScheduled(CFSocketRef s
) {
237 return (s
->_socketSetCount
> 0);
240 CF_INLINE
void __CFSocketEstablishAddress(CFSocketRef s
) {
241 /* socket should already be locked */
242 uint8_t name
[MAX_SOCKADDR_LEN
];
243 int namelen
= sizeof(name
);
244 if (__CFSocketIsValid(s
) && NULL
== s
->_address
&& INVALID_SOCKET
!= s
->_socket
&& 0 == getsockname(s
->_socket
, (struct sockaddr
*)name
, (socklen_t
*)&namelen
) && NULL
!= name
&& 0 < namelen
) {
245 s
->_address
= CFDataCreate(CFGetAllocator(s
), name
, namelen
);
249 CF_INLINE
void __CFSocketEstablishPeerAddress(CFSocketRef s
) {
250 /* socket should already be locked */
251 uint8_t name
[MAX_SOCKADDR_LEN
];
252 int namelen
= sizeof(name
);
253 if (__CFSocketIsValid(s
) && NULL
== s
->_peerAddress
&& INVALID_SOCKET
!= s
->_socket
&& 0 == getpeername(s
->_socket
, (struct sockaddr
*)name
, (socklen_t
*)&namelen
) && NULL
!= name
&& 0 < namelen
) {
254 s
->_peerAddress
= CFDataCreate(CFGetAllocator(s
), name
, namelen
);
258 static Boolean
__CFNativeSocketIsValid(CFSocketNativeHandle sock
) {
259 SInt32 flags
= fcntl(sock
, F_GETFL
, 0);
260 return !(0 > flags
&& EBADF
== thread_errno());
263 CF_INLINE Boolean
__CFSocketFdClr(CFSocketNativeHandle sock
, CFMutableDataRef fdSet
) {
264 /* returns true if a change occurred, false otherwise */
265 Boolean retval
= false;
266 if (INVALID_SOCKET
!= sock
&& 0 <= sock
) {
267 CFIndex numFds
= NBBY
* CFDataGetLength(fdSet
);
270 fds_bits
= (fd_mask
*)CFDataGetMutableBytePtr(fdSet
);
271 if (FD_ISSET(sock
, (fd_set
*)fds_bits
)) {
273 FD_CLR(sock
, (fd_set
*)fds_bits
);
280 static SInt32
__CFSocketCreateWakeupSocketPair(void) {
281 return socketpair(PF_LOCAL
, SOCK_DGRAM
, 0, __CFWakeupSocketPair
);
285 // Version 0 RunLoopSources set a mask in an FD set to control what socket activity we hear about.
286 CF_INLINE Boolean
__CFSocketSetFDForRead(CFSocketRef s
) {
287 return __CFSocketFdSet(s
->_socket
, __CFReadSocketsFds
);
290 CF_INLINE Boolean
__CFSocketClearFDForRead(CFSocketRef s
) {
291 return __CFSocketFdClr(s
->_socket
, __CFReadSocketsFds
);
294 CF_INLINE Boolean
__CFSocketSetFDForWrite(CFSocketRef s
) {
295 return __CFSocketFdSet(s
->_socket
, __CFWriteSocketsFds
);
298 CF_INLINE Boolean
__CFSocketClearFDForWrite(CFSocketRef s
) {
299 return __CFSocketFdClr(s
->_socket
, __CFWriteSocketsFds
);
303 // CFNetwork needs to call this, especially for Win32 to get WSAStartup
304 static void __CFSocketInitializeSockets(void) {
305 __CFWriteSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
);
306 __CFReadSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
);
307 __CFWriteSocketsFds
= CFDataCreateMutable(kCFAllocatorSystemDefault
, 0);
308 __CFReadSocketsFds
= CFDataCreateMutable(kCFAllocatorSystemDefault
, 0);
309 zeroLengthData
= CFDataCreateMutable(kCFAllocatorSystemDefault
, 0);
310 if (0 > __CFSocketCreateWakeupSocketPair()) {
311 CFLog(kCFLogLevelWarning
, CFSTR("*** Could not create wakeup socket pair for CFSocket!!!"));
314 /* wakeup sockets must be non-blocking */
315 ioctlsocket(__CFWakeupSocketPair
[0], FIONBIO
, &yes
);
316 ioctlsocket(__CFWakeupSocketPair
[1], FIONBIO
, &yes
);
317 __CFSocketFdSet(__CFWakeupSocketPair
[1], __CFReadSocketsFds
);
321 static CFRunLoopRef
__CFSocketCopyRunLoopToWakeUp(CFSocketRef s
) {
322 CFRunLoopRef rl
= NULL
;
323 SInt32 idx
, cnt
= CFArrayGetCount(s
->_runLoops
);
325 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(s
->_runLoops
, 0);
326 for (idx
= 1; NULL
!= rl
&& idx
< cnt
; idx
++) {
327 CFRunLoopRef value
= (CFRunLoopRef
)CFArrayGetValueAtIndex(s
->_runLoops
, idx
);
328 if (value
!= rl
) rl
= NULL
;
330 if (NULL
== rl
) { /* more than one different rl, so we must pick one */
331 /* ideally, this would be a run loop which isn't also in a
332 * signaled state for this or another source, but that's tricky;
333 * we pick one that is running in an appropriate mode for this
334 * source, and from those if possible one that is waiting; then
335 * we move this run loop to the end of the list to scramble them
336 * a bit, and always search from the front */
337 Boolean foundIt
= false, foundBackup
= false;
339 for (idx
= 0; !foundIt
&& idx
< cnt
; idx
++) {
340 CFRunLoopRef value
= (CFRunLoopRef
)CFArrayGetValueAtIndex(s
->_runLoops
, idx
);
341 CFStringRef currentMode
= CFRunLoopCopyCurrentMode(value
);
342 if (NULL
!= currentMode
) {
343 if (CFRunLoopContainsSource(value
, s
->_source0
, currentMode
)) {
344 if (CFRunLoopIsWaiting(value
)) {
347 } else if (!foundBackup
) {
352 CFRelease(currentMode
);
355 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(s
->_runLoops
, foundIdx
);
357 CFArrayRemoveValueAtIndex(s
->_runLoops
, foundIdx
);
358 CFArrayAppendValue(s
->_runLoops
, rl
);
366 // If callBackNow, we immediately do client callbacks, else we have to signal a v0 RunLoopSource so the
367 // callbacks can happen in another thread.
368 static void __CFSocketHandleWrite(CFSocketRef s
, Boolean callBackNow
) {
369 SInt32 errorCode
= 0;
370 int errorSize
= sizeof(errorCode
);
371 CFOptionFlags writeCallBacksAvailable
;
373 if (!CFSocketIsValid(s
)) return;
374 if (0 != (s
->_f
.client
& kCFSocketLeaveErrors
) || 0 != getsockopt(s
->_socket
, SOL_SOCKET
, SO_ERROR
, (void *)&errorCode
, (socklen_t
*)&errorSize
)) errorCode
= 0; // cast for WinSock bad API
375 #if defined(LOG_CFSOCKET)
376 if (errorCode
) fprintf(stdout
, "error %ld on socket %d\n", errorCode
, s
->_socket
);
377 #endif /* LOG_CFSOCKET */
379 writeCallBacksAvailable
= __CFSocketCallBackTypes(s
) & (kCFSocketWriteCallBack
| kCFSocketConnectCallBack
);
380 if ((s
->_f
.client
& kCFSocketConnectCallBack
) != 0) writeCallBacksAvailable
&= ~kCFSocketConnectCallBack
;
381 if (!__CFSocketIsValid(s
) || ((s
->_f
.disabled
& writeCallBacksAvailable
) == writeCallBacksAvailable
)) {
385 s
->_errorCode
= errorCode
;
386 __CFSocketSetWriteSignalled(s
);
387 #if defined(LOG_CFSOCKET)
388 fprintf(stdout
, "write signaling source for socket %d\n", s
->_socket
);
389 #endif /* LOG_CFSOCKET */
391 __CFSocketDoCallback(s
, NULL
, NULL
, 0);
394 CFRunLoopSourceSignal(s
->_source0
);
395 rl
= __CFSocketCopyRunLoopToWakeUp(s
);
404 static void __CFSocketHandleRead(CFSocketRef s
, Boolean causedByTimeout
)
406 CFDataRef data
= NULL
, address
= NULL
;
407 CFSocketNativeHandle sock
= INVALID_SOCKET
;
408 if (!CFSocketIsValid(s
)) return;
409 if (__CFSocketReadCallBackType(s
) == kCFSocketDataCallBack
) {
410 uint8_t bufferArray
[MAX_CONNECTION_ORIENTED_DATA_SIZE
], *buffer
;
411 uint8_t name
[MAX_SOCKADDR_LEN
];
412 int namelen
= sizeof(name
);
414 if (__CFSocketIsConnectionOriented(s
)) {
415 buffer
= bufferArray
;
416 recvlen
= recvfrom(s
->_socket
, buffer
, MAX_CONNECTION_ORIENTED_DATA_SIZE
, 0, (struct sockaddr
*)name
, (socklen_t
*)&namelen
);
418 buffer
= malloc(MAX_DATA_SIZE
);
419 if (buffer
) recvlen
= recvfrom(s
->_socket
, buffer
, MAX_DATA_SIZE
, 0, (struct sockaddr
*)name
, (socklen_t
*)&namelen
);
421 #if defined(LOG_CFSOCKET)
422 fprintf(stdout
, "read %ld bytes on socket %d\n", recvlen
, s
->_socket
);
423 #endif /* LOG_CFSOCKET */
425 //??? should return error if <0
426 /* zero-length data is the signal for perform to invalidate */
427 data
= CFRetain(zeroLengthData
);
429 data
= CFDataCreate(CFGetAllocator(s
), buffer
, recvlen
);
431 if (buffer
&& buffer
!= bufferArray
) free(buffer
);
433 if (!__CFSocketIsValid(s
)) {
438 __CFSocketSetReadSignalled(s
);
439 if (NULL
!= name
&& 0 < namelen
) {
440 //??? possible optimizations: uniquing; storing last value
441 address
= CFDataCreate(CFGetAllocator(s
), name
, namelen
);
442 } else if (__CFSocketIsConnectionOriented(s
)) {
443 if (NULL
== s
->_peerAddress
) __CFSocketEstablishPeerAddress(s
);
444 if (NULL
!= s
->_peerAddress
) address
= CFRetain(s
->_peerAddress
);
446 if (NULL
== address
) {
447 address
= CFRetain(zeroLengthData
);
449 if (NULL
== s
->_dataQueue
) {
450 s
->_dataQueue
= CFArrayCreateMutable(CFGetAllocator(s
), 0, &kCFTypeArrayCallBacks
);
452 if (NULL
== s
->_addressQueue
) {
453 s
->_addressQueue
= CFArrayCreateMutable(CFGetAllocator(s
), 0, &kCFTypeArrayCallBacks
);
455 CFArrayAppendValue(s
->_dataQueue
, data
);
457 CFArrayAppendValue(s
->_addressQueue
, address
);
460 && (s
->_f
.client
& kCFSocketDataCallBack
) != 0 && (s
->_f
.disabled
& kCFSocketDataCallBack
) == 0
461 && __CFSocketIsScheduled(s
)
463 __CFSpinLock(&__CFActiveSocketsLock
);
464 /* restore socket to fds */
465 __CFSocketSetFDForRead(s
);
466 __CFSpinUnlock(&__CFActiveSocketsLock
);
468 } else if (__CFSocketReadCallBackType(s
) == kCFSocketAcceptCallBack
) {
469 uint8_t name
[MAX_SOCKADDR_LEN
];
470 int namelen
= sizeof(name
);
471 sock
= accept(s
->_socket
, (struct sockaddr
*)name
, (socklen_t
*)&namelen
);
472 if (INVALID_SOCKET
== sock
) {
473 //??? should return error
476 if (NULL
!= name
&& 0 < namelen
) {
477 address
= CFDataCreate(CFGetAllocator(s
), name
, namelen
);
479 address
= CFRetain(zeroLengthData
);
482 if (!__CFSocketIsValid(s
)) {
488 __CFSocketSetReadSignalled(s
);
489 if (NULL
== s
->_dataQueue
) {
490 s
->_dataQueue
= CFArrayCreateMutable(CFGetAllocator(s
), 0, NULL
);
492 if (NULL
== s
->_addressQueue
) {
493 s
->_addressQueue
= CFArrayCreateMutable(CFGetAllocator(s
), 0, &kCFTypeArrayCallBacks
);
495 CFArrayAppendValue(s
->_dataQueue
, (void *)(uintptr_t)sock
);
496 CFArrayAppendValue(s
->_addressQueue
, address
);
498 if ((s
->_f
.client
& kCFSocketAcceptCallBack
) != 0 && (s
->_f
.disabled
& kCFSocketAcceptCallBack
) == 0
499 && __CFSocketIsScheduled(s
)
501 __CFSpinLock(&__CFActiveSocketsLock
);
502 /* restore socket to fds */
503 __CFSocketSetFDForRead(s
);
504 __CFSpinUnlock(&__CFActiveSocketsLock
);
508 if (!__CFSocketIsValid(s
) || (s
->_f
.disabled
& kCFSocketReadCallBack
) != 0) {
513 if (causedByTimeout
) {
514 #if defined(LOG_CFSOCKET)
515 fprintf(stdout
, "TIMEOUT RECEIVED - WILL SIGNAL IMMEDIATELY TO FLUSH (%d buffered)\n", s
->_bytesToBufferPos
);
516 #endif /* LOG_CFSOCKET */
517 /* we've got a timeout, but no bytes read. Ignore the timeout. */
518 if (s
->_bytesToBufferPos
== 0) {
519 #if defined(LOG_CFSOCKET)
520 fprintf(stdout
, "TIMEOUT - but no bytes, restoring to active set\n");
524 __CFSpinLock(&__CFActiveSocketsLock
);
525 /* restore socket to fds */
526 __CFSocketSetFDForRead(s
);
527 __CFSpinUnlock(&__CFActiveSocketsLock
);
531 } else if (s
->_bytesToBuffer
!= 0 && ! s
->_atEOF
) {
534 CFIndex ctRemaining
= s
->_bytesToBuffer
- s
->_bytesToBufferPos
;
536 /* if our buffer has room, we go ahead and buffer */
537 if (ctRemaining
> 0) {
538 base
= CFDataGetMutableBytePtr(s
->_readBuffer
);
541 ctRead
= read(CFSocketGetNative(s
), &base
[s
->_bytesToBufferPos
], ctRemaining
);
542 } while (ctRead
== -1 && errno
== EAGAIN
);
546 s
->_bufferedReadError
= errno
;
548 #if defined(LOG_CFSOCKET)
549 fprintf(stderr
, "BUFFERED READ GOT ERROR %d\n", errno
);
550 #endif /* LOG_CFSOCKET */
554 #if defined(LOG_CFSOCKET)
555 fprintf(stdout
, "DONE READING (EOF) - GOING TO SIGNAL\n");
556 #endif /* LOG_CFSOCKET */
561 s
->_bytesToBufferPos
+= ctRead
;
562 if (s
->_bytesToBuffer
!= s
->_bytesToBufferPos
) {
563 #if defined(LOG_CFSOCKET)
564 fprintf(stdout
, "READ %d - need %d MORE - GOING BACK FOR MORE\n", ctRead
, s
->_bytesToBuffer
- s
->_bytesToBufferPos
);
565 #endif /* LOG_CFSOCKET */
566 __CFSpinLock(&__CFActiveSocketsLock
);
567 /* restore socket to fds */
568 __CFSocketSetFDForRead(s
);
569 __CFSpinUnlock(&__CFActiveSocketsLock
);
573 #if defined(LOG_CFSOCKET)
574 fprintf(stdout
, "DONE READING (read %d bytes) - GOING TO SIGNAL\n", ctRead
);
575 #endif /* LOG_CFSOCKET */
581 __CFSocketSetReadSignalled(s
);
583 #if defined(LOG_CFSOCKET)
584 fprintf(stdout
, "read signaling source for socket %d\n", s
->_socket
);
585 #endif /* LOG_CFSOCKET */
586 CFRunLoopSourceSignal(s
->_source0
);
587 CFRunLoopRef rl
= __CFSocketCopyRunLoopToWakeUp(s
);
595 static struct timeval
* intervalToTimeval(CFTimeInterval timeout
, struct timeval
* tv
)
600 tv
->tv_sec
= (0 >= timeout
|| INT_MAX
<= timeout
) ? INT_MAX
: (int)(float)floor(timeout
);
601 tv
->tv_usec
= (int)((timeout
- floor(timeout
)) * 1.0E6
);
606 /* note that this returns a pointer to the min value, which won't have changed during
607 the dictionary apply, since we've got the active sockets lock held */
608 static void _calcMinTimeout_locked(const void* val
, void* ctxt
)
610 CFSocketRef s
= (CFSocketRef
) val
;
611 struct timeval
** minTime
= (struct timeval
**) ctxt
;
612 if (timerisset(&s
->_readBufferTimeout
) && (*minTime
== NULL
|| timercmp(&s
->_readBufferTimeout
, *minTime
, <)))
613 *minTime
= &s
->_readBufferTimeout
;
616 void __CFSocketSetReadBufferTimeout(CFSocketRef s
, CFTimeInterval timeout
)
618 struct timeval timeoutVal
;
620 intervalToTimeval(timeout
, &timeoutVal
);
622 /* lock ordering is socket lock, activesocketslock */
623 /* activesocketslock protects our timeout calculation */
625 __CFSpinLock(&__CFActiveSocketsLock
);
626 if (timercmp(&s
->_readBufferTimeout
, &timeoutVal
, !=)) {
627 s
->_readBufferTimeout
= timeoutVal
;
628 __CFReadSocketsTimeoutInvalid
= true;
630 __CFSpinUnlock(&__CFActiveSocketsLock
);
634 void __CFSocketSetReadBufferLength(CFSocketRef s
, CFIndex length
)
637 if (s
->_bytesToBuffer
!= length
) {
638 if (s
->_bytesToBufferPos
!= 0 && s
->_bytesToBufferReadPos
!= 0) {
639 /* As originally envisaged, you were supposed to be sure to drain the buffer before
640 * issuing another request on the socket. In practice, there seem to be times when we want to re-use
641 * the stream (or perhaps, are on our way to closing it out) and this policy doesn't work so well.
642 * So, if someone changes the buffer size while we have bytes already buffered, we put them
643 * aside and use them to satisfy any subsequent reads.
646 fprintf(stderr
, "%s(%d): WARNING: shouldn't set read buffer length while data is still in the read buffer\n\n", __FUNCTION__
, __LINE__
);
648 if (s
->_leftoverBytes
== NULL
)
649 s
->_leftoverBytes
= CFDataCreateMutable(CFGetAllocator(s
), 0);
651 /* append the current buffered bytes over. We'll keep draining _leftoverBytes while we have them... */
652 CFDataAppendBytes(s
->_leftoverBytes
, CFDataGetBytePtr(s
->_readBuffer
) + s
->_bytesToBufferPos
, s
->_bytesToBufferReadPos
- s
->_bytesToBufferPos
);
653 CFRelease(s
->_readBuffer
);
654 s
->_readBuffer
= NULL
;
656 s
->_bytesToBuffer
= 0;
657 s
->_bytesToBufferPos
= 0;
658 s
->_bytesToBufferReadPos
= 0;
661 s
->_bytesToBuffer
= 0;
662 s
->_bytesToBufferPos
= 0;
663 s
->_bytesToBufferReadPos
= 0;
664 if (s
->_readBuffer
) {
665 CFRelease(s
->_readBuffer
);
666 s
->_readBuffer
= NULL
;
669 /* if the buffer shrank, we can re-use the old one */
670 if (length
> s
->_bytesToBuffer
) {
671 if (s
->_readBuffer
) {
672 CFRelease(s
->_readBuffer
);
673 s
->_readBuffer
= NULL
;
677 s
->_bytesToBuffer
= length
;
678 s
->_bytesToBufferPos
= 0;
679 s
->_bytesToBufferReadPos
= 0;
680 if (s
->_readBuffer
== NULL
) {
681 s
->_readBuffer
= CFDataCreateMutable(kCFAllocatorDefault
, length
);
682 CFDataSetLength(s
->_readBuffer
, length
);
688 __CFSocketSetReadBufferTimeout(s
, 0.0);
691 CFIndex
__CFSocketRead(CFSocketRef s
, UInt8
* buffer
, CFIndex length
, int* error
)
693 #if defined(LOG_CFSOCKET)
694 fprintf(stdout
, "READING BYTES FOR SOCKET %d (%d buffered, out of %d desired, eof = %d, err = %d)\n", s
->_socket
, s
->_bytesToBufferPos
, s
->_bytesToBuffer
, s
->_atEOF
, s
->_bufferedReadError
);
695 #endif /* LOG_CFSOCKET */
703 /* Any leftover buffered bytes? */
704 if (s
->_leftoverBytes
) {
705 CFIndex ctBuffer
= CFDataGetLength(s
->_leftoverBytes
);
707 fprintf(stderr
, "%s(%d): WARNING: Draining %d leftover bytes first\n\n", __FUNCTION__
, __LINE__
, ctBuffer
);
709 if (ctBuffer
> length
)
711 memcpy(buffer
, CFDataGetBytePtr(s
->_leftoverBytes
), ctBuffer
);
712 if (ctBuffer
< CFDataGetLength(s
->_leftoverBytes
))
713 CFDataReplaceBytes(s
->_leftoverBytes
, CFRangeMake(0, ctBuffer
), NULL
, 0);
715 CFRelease(s
->_leftoverBytes
);
716 s
->_leftoverBytes
= NULL
;
722 /* return whatever we've buffered */
723 if (s
->_bytesToBuffer
!= 0) {
724 CFIndex ctBuffer
= s
->_bytesToBufferPos
- s
->_bytesToBufferReadPos
;
726 /* drain our buffer first */
727 if (ctBuffer
> length
)
729 memcpy(buffer
, CFDataGetBytePtr(s
->_readBuffer
) + s
->_bytesToBufferReadPos
, ctBuffer
);
730 s
->_bytesToBufferReadPos
+= ctBuffer
;
731 if (s
->_bytesToBufferReadPos
== s
->_bytesToBufferPos
) {
732 #if defined(LOG_CFSOCKET)
733 fprintf(stdout
, "DRAINED BUFFER - SHOULD START BUFFERING AGAIN!\n");
734 #endif /* LOG_CFSOCKET */
735 s
->_bytesToBufferPos
= 0;
736 s
->_bytesToBufferReadPos
= 0;
739 #if defined(LOG_CFSOCKET)
740 fprintf(stdout
, "SLURPED %d BYTES FROM BUFFER %d LEFT TO READ!\n", ctBuffer
, length
);
741 #endif /* LOG_CFSOCKET */
747 /* nothing buffered, or no buffer selected */
749 /* Did we get an error on a previous read (or buffered read)? */
750 if (s
->_bufferedReadError
!= 0) {
751 #if defined(LOG_CFSOCKET)
752 fprintf(stdout
, "RETURNING ERROR %d\n", s
->_bufferedReadError
);
753 #endif /* LOG_CFSOCKET */
754 *error
= s
->_bufferedReadError
;
759 /* nothing buffered, if we've hit eof, don't bother reading any more */
761 #if defined(LOG_CFSOCKET)
762 fprintf(stdout
, "RETURNING EOF\n");
763 #endif /* LOG_CFSOCKET */
769 result
= read(CFSocketGetNative(s
), buffer
, length
);
770 #if defined(LOG_CFSOCKET)
771 fprintf(stdout
, "READ %d bytes", result
);
772 #endif /* LOG_CFSOCKET */
775 /* note that we hit EOF */
777 } else if (result
< 0) {
780 /* if it wasn't EAGAIN, record it (although we shouldn't get called again) */
781 if (*error
!= EAGAIN
) {
782 s
->_bufferedReadError
= *error
;
792 Boolean
__CFSocketGetBytesAvailable(CFSocketRef s
, CFIndex
* ctBytesAvailable
)
794 CFIndex ctBuffer
= s
->_bytesToBufferPos
- s
->_bytesToBufferReadPos
;
796 *ctBytesAvailable
= ctBuffer
;
800 #if ! defined(__WIN32__)
801 int bytesAvailable
, intLen
= sizeof(bytesAvailable
);
802 result
= getsockopt(CFSocketGetNative(s
), SOL_SOCKET
, SO_NREAD
, &bytesAvailable
, (void *)&intLen
);
804 unsigned long bytesAvailable
;
805 result
= ioctlsocket(CFSocketGetNative(s
), FIONREAD
, &bytesAvailable
);
809 *ctBytesAvailable
= (CFIndex
) bytesAvailable
;
814 #if defined(LOG_CFSOCKET)
815 static void __CFSocketWriteSocketList(CFArrayRef sockets
, CFDataRef fdSet
, Boolean onlyIfSet
) {
816 fd_set
*tempfds
= (fd_set
*)CFDataGetBytePtr(fdSet
);
818 for (idx
= 0, cnt
= CFArrayGetCount(sockets
); idx
< cnt
; idx
++) {
819 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(sockets
, idx
);
820 if (FD_ISSET(s
->_socket
, tempfds
)) {
821 fprintf(stdout
, "%d ", s
->_socket
);
822 } else if (!onlyIfSet
) {
823 fprintf(stdout
, "(%d) ", s
->_socket
);
827 #endif /* LOG_CFSOCKET */
830 __attribute__ ((noreturn
)) // mostly interesting for shutting up a warning
831 #endif /* __GNUC__ */
832 static void __CFSocketManager(void * arg
)
834 if (objc_collecting_enabled()) auto_zone_register_thread(auto_zone());
835 SInt32 nrfds
, maxnrfds
, fdentries
= 1;
837 fd_set
*exceptfds
= NULL
;
838 fd_set
*writefds
= (fd_set
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, fdentries
* sizeof(fd_mask
), 0);
839 fd_set
*readfds
= (fd_set
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, fdentries
* sizeof(fd_mask
), 0);
843 CFMutableArrayRef selectedWriteSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
844 CFMutableArrayRef selectedReadSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
845 CFIndex selectedWriteSocketsIndex
= 0, selectedReadSocketsIndex
= 0;
848 struct timeval
* pTimeout
= NULL
;
849 struct timeval timeBeforeSelect
;
852 __CFSpinLock(&__CFActiveSocketsLock
);
853 __CFSocketManagerIteration
++;
854 #if defined(LOG_CFSOCKET)
855 fprintf(stdout
, "socket manager iteration %lu looking at read sockets ", __CFSocketManagerIteration
);
856 __CFSocketWriteSocketList(__CFReadSockets
, __CFReadSocketsFds
, FALSE
);
857 if (0 < CFArrayGetCount(__CFWriteSockets
)) {
858 fprintf(stdout
, " and write sockets ");
859 __CFSocketWriteSocketList(__CFWriteSockets
, __CFWriteSocketsFds
, FALSE
);
861 fprintf(stdout
, "\n");
862 #endif /* LOG_CFSOCKET */
863 rfds
= __CFSocketFdGetSize(__CFReadSocketsFds
);
864 wfds
= __CFSocketFdGetSize(__CFWriteSocketsFds
);
865 maxnrfds
= __CFMax(rfds
, wfds
);
866 if (maxnrfds
> fdentries
* (int)NFDBITS
) {
867 fdentries
= (maxnrfds
+ NFDBITS
- 1) / NFDBITS
;
868 writefds
= (fd_set
*)CFAllocatorReallocate(kCFAllocatorSystemDefault
, writefds
, fdentries
* sizeof(fd_mask
), 0);
869 readfds
= (fd_set
*)CFAllocatorReallocate(kCFAllocatorSystemDefault
, readfds
, fdentries
* sizeof(fd_mask
), 0);
871 memset(writefds
, 0, fdentries
* sizeof(fd_mask
));
872 memset(readfds
, 0, fdentries
* sizeof(fd_mask
));
873 CFDataGetBytes(__CFWriteSocketsFds
, CFRangeMake(0, CFDataGetLength(__CFWriteSocketsFds
)), (UInt8
*)writefds
);
874 CFDataGetBytes(__CFReadSocketsFds
, CFRangeMake(0, CFDataGetLength(__CFReadSocketsFds
)), (UInt8
*)readfds
);
876 if (__CFReadSocketsTimeoutInvalid
) {
877 struct timeval
* minTimeout
= NULL
;
878 __CFReadSocketsTimeoutInvalid
= false;
879 #if defined(LOG_CFSOCKET)
880 fprintf(stdout
, "Figuring out which sockets have timeouts...\n");
881 #endif /* LOG_CFSOCKET */
882 CFArrayApplyFunction(__CFReadSockets
, CFRangeMake(0, CFArrayGetCount(__CFReadSockets
)), _calcMinTimeout_locked
, (void*) &minTimeout
);
884 if (minTimeout
== NULL
) {
885 #if defined(LOG_CFSOCKET)
886 fprintf(stdout
, "No one wants a timeout!\n");
887 #endif /* LOG_CFSOCKET */
890 #if defined(LOG_CFSOCKET)
891 fprintf(stdout
, "timeout will be %d, %d!\n", minTimeout
->tv_sec
, minTimeout
->tv_usec
);
892 #endif /* LOG_CFSOCKET */
899 #if defined(LOG_CFSOCKET)
900 fprintf(stdout
, "select will have a %d, %d timeout\n", pTimeout
->tv_sec
, pTimeout
->tv_usec
);
901 #endif /* LOG_CFSOCKET */
902 gettimeofday(&timeBeforeSelect
, NULL
);
905 __CFSpinUnlock(&__CFActiveSocketsLock
);
907 nrfds
= select(maxnrfds
, readfds
, writefds
, exceptfds
, pTimeout
);
909 #if defined(LOG_CFSOCKET)
910 fprintf(stdout
, "socket manager woke from select, ret=%ld\n", nrfds
);
911 #endif /* LOG_CFSOCKET */
914 * select returned a timeout
917 struct timeval timeAfterSelect
;
918 struct timeval deltaTime
;
919 gettimeofday(&timeAfterSelect
, NULL
);
920 /* timeBeforeSelect becomes the delta */
921 timersub(&timeAfterSelect
, &timeBeforeSelect
, &deltaTime
);
923 #if defined(LOG_CFSOCKET)
924 fprintf(stdout
, "Socket manager received timeout - kicking off expired reads (expired delta %d, %d)\n", deltaTime
.tv_sec
, deltaTime
.tv_usec
);
925 #endif /* LOG_CFSOCKET */
927 __CFSpinLock(&__CFActiveSocketsLock
);
930 cnt
= CFArrayGetCount(__CFReadSockets
);
931 for (idx
= 0; idx
< cnt
; idx
++) {
932 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFReadSockets
, idx
);
933 if (timerisset(&s
->_readBufferTimeout
)) {
934 CFSocketNativeHandle sock
= s
->_socket
;
935 // We might have an new element in __CFReadSockets that we weren't listening to,
936 // in which case we must be sure not to test a bit in the fdset that is
937 // outside our mask size.
938 Boolean sockInBounds
= (0 <= sock
&& sock
< maxnrfds
);
939 /* if this sockets timeout is less than or equal elapsed time, then signal it */
940 if (INVALID_SOCKET
!= sock
&& sockInBounds
&& timercmp(&s
->_readBufferTimeout
, &deltaTime
, <=)) {
941 #if defined(LOG_CFSOCKET)
942 fprintf(stdout
, "Expiring socket %d (delta %d, %d)\n", sock
, s
->_readBufferTimeout
.tv_sec
, s
->_readBufferTimeout
.tv_usec
);
943 #endif /* LOG_CFSOCKET */
944 CFArraySetValueAtIndex(selectedReadSockets
, selectedReadSocketsIndex
, s
);
945 selectedReadSocketsIndex
++;
946 /* socket is removed from fds here, will be restored in read handling or in perform function */
947 if (!tempfds
) tempfds
= (fd_set
*)CFDataGetMutableBytePtr(__CFReadSocketsFds
);
948 FD_CLR(sock
, tempfds
);
953 __CFSpinUnlock(&__CFActiveSocketsLock
);
955 /* and below, we dispatch through the normal read dispatch mechanism */
959 SInt32 selectError
= __CFSocketLastError();
960 #if defined(LOG_CFSOCKET)
961 fprintf(stdout
, "socket manager received error %ld from select\n", selectError
);
962 #endif /* LOG_CFSOCKET */
963 if (EBADF
== selectError
) {
964 CFMutableArrayRef invalidSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
965 __CFSpinLock(&__CFActiveSocketsLock
);
966 cnt
= CFArrayGetCount(__CFWriteSockets
);
967 for (idx
= 0; idx
< cnt
; idx
++) {
968 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFWriteSockets
, idx
);
969 if (!__CFNativeSocketIsValid(s
->_socket
)) {
970 #if defined(LOG_CFSOCKET)
971 fprintf(stdout
, "socket manager found write socket %d invalid\n", s
->_socket
);
972 #endif /* LOG_CFSOCKET */
973 CFArrayAppendValue(invalidSockets
, s
);
976 cnt
= CFArrayGetCount(__CFReadSockets
);
977 for (idx
= 0; idx
< cnt
; idx
++) {
978 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFReadSockets
, idx
);
979 if (!__CFNativeSocketIsValid(s
->_socket
)) {
980 #if defined(LOG_CFSOCKET)
981 fprintf(stdout
, "socket manager found read socket %d invalid\n", s
->_socket
);
982 #endif /* LOG_CFSOCKET */
983 CFArrayAppendValue(invalidSockets
, s
);
986 __CFSpinUnlock(&__CFActiveSocketsLock
);
988 cnt
= CFArrayGetCount(invalidSockets
);
989 for (idx
= 0; idx
< cnt
; idx
++) {
990 CFSocketInvalidate(((CFSocketRef
)CFArrayGetValueAtIndex(invalidSockets
, idx
)));
992 CFRelease(invalidSockets
);
996 if (FD_ISSET(__CFWakeupSocketPair
[1], readfds
)) {
997 recv(__CFWakeupSocketPair
[1], buffer
, sizeof(buffer
), 0);
998 #if defined(LOG_CFSOCKET)
999 fprintf(stdout
, "socket manager received %c on wakeup socket\n", buffer
[0]);
1000 #endif /* LOG_CFSOCKET */
1002 __CFSpinLock(&__CFActiveSocketsLock
);
1004 cnt
= CFArrayGetCount(__CFWriteSockets
);
1005 for (idx
= 0; idx
< cnt
; idx
++) {
1006 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFWriteSockets
, idx
);
1007 CFSocketNativeHandle sock
= s
->_socket
;
1008 // We might have an new element in __CFWriteSockets that we weren't listening to,
1009 // in which case we must be sure not to test a bit in the fdset that is
1010 // outside our mask size.
1011 Boolean sockInBounds
= (0 <= sock
&& sock
< maxnrfds
);
1012 if (INVALID_SOCKET
!= sock
&& sockInBounds
) {
1013 if (FD_ISSET(sock
, writefds
)) {
1014 CFArraySetValueAtIndex(selectedWriteSockets
, selectedWriteSocketsIndex
, s
);
1015 selectedWriteSocketsIndex
++;
1016 /* socket is removed from fds here, restored by CFSocketReschedule */
1017 if (!tempfds
) tempfds
= (fd_set
*)CFDataGetMutableBytePtr(__CFWriteSocketsFds
);
1018 FD_CLR(sock
, tempfds
);
1023 cnt
= CFArrayGetCount(__CFReadSockets
);
1024 for (idx
= 0; idx
< cnt
; idx
++) {
1025 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFReadSockets
, idx
);
1026 CFSocketNativeHandle sock
= s
->_socket
;
1027 // We might have an new element in __CFReadSockets that we weren't listening to,
1028 // in which case we must be sure not to test a bit in the fdset that is
1029 // outside our mask size.
1030 Boolean sockInBounds
= (0 <= sock
&& sock
< maxnrfds
);
1031 if (INVALID_SOCKET
!= sock
&& sockInBounds
&& FD_ISSET(sock
, readfds
)) {
1032 CFArraySetValueAtIndex(selectedReadSockets
, selectedReadSocketsIndex
, s
);
1033 selectedReadSocketsIndex
++;
1034 /* socket is removed from fds here, will be restored in read handling or in perform function */
1035 if (!tempfds
) tempfds
= (fd_set
*)CFDataGetMutableBytePtr(__CFReadSocketsFds
);
1036 FD_CLR(sock
, tempfds
);
1039 __CFSpinUnlock(&__CFActiveSocketsLock
);
1041 for (idx
= 0; idx
< selectedWriteSocketsIndex
; idx
++) {
1042 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(selectedWriteSockets
, idx
);
1043 if (kCFNull
== (CFNullRef
)s
) continue;
1044 #if defined(LOG_CFSOCKET)
1045 fprintf(stdout
, "socket manager signaling socket %d for write\n", s
->_socket
);
1046 #endif /* LOG_CFSOCKET */
1047 __CFSocketHandleWrite(s
, FALSE
);
1048 CFArraySetValueAtIndex(selectedWriteSockets
, idx
, kCFNull
);
1050 selectedWriteSocketsIndex
= 0;
1052 for (idx
= 0; idx
< selectedReadSocketsIndex
; idx
++) {
1053 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(selectedReadSockets
, idx
);
1054 if (kCFNull
== (CFNullRef
)s
) continue;
1055 #if defined(LOG_CFSOCKET)
1056 fprintf(stdout
, "socket manager signaling socket %d for read\n", s
->_socket
);
1057 #endif /* LOG_CFSOCKET */
1058 __CFSocketHandleRead(s
, nrfds
== 0);
1059 CFArraySetValueAtIndex(selectedReadSockets
, idx
, kCFNull
);
1061 selectedReadSocketsIndex
= 0;
1063 if (objc_collecting_enabled()) auto_zone_unregister_thread(auto_zone());
1066 static CFStringRef
__CFSocketCopyDescription(CFTypeRef cf
) {
1067 CFSocketRef s
= (CFSocketRef
)cf
;
1068 CFMutableStringRef result
;
1069 CFStringRef contextDesc
= NULL
;
1070 void *contextInfo
= NULL
;
1071 CFStringRef (*contextCopyDescription
)(const void *info
) = NULL
;
1072 result
= CFStringCreateMutable(CFGetAllocator(s
), 0);
1074 void *addr
= s
->_callout
;
1076 const char *name
= (dladdr(addr
, &info
) && info
.dli_saddr
== addr
&& info
.dli_sname
) ? info
.dli_sname
: "???";
1077 CFStringAppendFormat(result
, NULL
, CFSTR("<CFSocket %p [%p]>{valid = %s, type = %d, socket = %d, socket set count = %ld,\n callback types = 0x%x, callout = %s (%p), source = %p,\n run loops = %@,\n context = "), cf
, CFGetAllocator(s
), (__CFSocketIsValid(s
) ? "Yes" : "No"), s
->_socketType
, s
->_socket
, s
->_socketSetCount
, __CFSocketCallBackTypes(s
), name
, addr
, s
->_source0
, s
->_runLoops
);
1078 contextInfo
= s
->_context
.info
;
1079 contextCopyDescription
= s
->_context
.copyDescription
;
1080 __CFSocketUnlock(s
);
1081 if (NULL
!= contextInfo
&& NULL
!= contextCopyDescription
) {
1082 contextDesc
= (CFStringRef
)contextCopyDescription(contextInfo
);
1084 if (NULL
== contextDesc
) {
1085 contextDesc
= CFStringCreateWithFormat(CFGetAllocator(s
), NULL
, CFSTR("<CFSocket context %p>"), contextInfo
);
1087 CFStringAppend(result
, contextDesc
);
1088 CFStringAppend(result
, CFSTR("}"));
1089 CFRelease(contextDesc
);
1093 static void __CFSocketDeallocate(CFTypeRef cf
) {
1094 /* Since CFSockets are cached, we can only get here sometime after being invalidated */
1095 CFSocketRef s
= (CFSocketRef
)cf
;
1096 if (NULL
!= s
->_address
) {
1097 CFRelease(s
->_address
);
1100 if (NULL
!= s
->_readBuffer
) {
1101 CFRelease(s
->_readBuffer
);
1102 s
->_readBuffer
= NULL
;
1104 if (NULL
!= s
->_leftoverBytes
) {
1105 CFRelease(s
->_leftoverBytes
);
1106 s
->_leftoverBytes
= NULL
;
1108 timerclear(&s
->_readBufferTimeout
);
1109 s
->_bytesToBuffer
= 0;
1110 s
->_bytesToBufferPos
= 0;
1111 s
->_bytesToBufferReadPos
= 0;
1113 s
->_bufferedReadError
= 0;
1116 static const CFRuntimeClass __CFSocketClass
= {
1121 __CFSocketDeallocate
,
1125 __CFSocketCopyDescription
1128 __private_extern__
void __CFSocketInitialize(void) {
1129 __kCFSocketTypeID
= _CFRuntimeRegisterClass(&__CFSocketClass
);
1132 CFTypeID
CFSocketGetTypeID(void) {
1133 return __kCFSocketTypeID
;
1135 static CFSocketRef
_CFSocketCreateWithNative(CFAllocatorRef allocator
, CFSocketNativeHandle sock
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
, Boolean useExistingInstance
) {
1138 int typeSize
= sizeof(memory
->_socketType
);
1139 __CFSpinLock(&__CFActiveSocketsLock
);
1140 if (NULL
== __CFReadSockets
) __CFSocketInitializeSockets();
1141 __CFSpinUnlock(&__CFActiveSocketsLock
);
1142 __CFSpinLock(&__CFAllSocketsLock
);
1143 if (NULL
== __CFAllSockets
) {
1144 __CFAllSockets
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, &kCFTypeDictionaryValueCallBacks
);
1146 if (INVALID_SOCKET
!= sock
&& CFDictionaryGetValueIfPresent(__CFAllSockets
, (void *)(uintptr_t)sock
, (const void **)&memory
)) {
1147 if (useExistingInstance
) {
1148 __CFSpinUnlock(&__CFAllSocketsLock
);
1152 #if defined(LOG_CFSOCKET)
1153 fprintf(stdout
, "useExistingInstance is FALSE, removing existing instance %d from __CFAllSockets\n", (int)memory
);
1154 #endif /* LOG_CFSOCKET */
1155 __CFSpinUnlock(&__CFAllSocketsLock
);
1156 CFSocketInvalidate(memory
);
1157 __CFSpinLock(&__CFAllSocketsLock
);
1160 memory
= (CFSocketRef
)_CFRuntimeCreateInstance(allocator
, __kCFSocketTypeID
, sizeof(struct __CFSocket
) - sizeof(CFRuntimeBase
), NULL
);
1161 if (NULL
== memory
) {
1162 __CFSpinUnlock(&__CFAllSocketsLock
);
1165 __CFSocketSetCallBackTypes(memory
, callBackTypes
);
1166 if (INVALID_SOCKET
!= sock
) __CFSocketSetValid(memory
);
1167 __CFSocketUnsetWriteSignalled(memory
);
1168 __CFSocketUnsetReadSignalled(memory
);
1169 memory
->_f
.client
= ((callBackTypes
& (~kCFSocketConnectCallBack
)) & (~kCFSocketWriteCallBack
)) | kCFSocketCloseOnInvalidate
;
1170 memory
->_f
.disabled
= 0;
1171 memory
->_f
.connected
= FALSE
;
1172 memory
->_f
.writableHint
= FALSE
;
1173 memory
->_f
.closeSignaled
= FALSE
;
1174 memory
->_lock
= CFSpinLockInit
;
1175 memory
->_writeLock
= CFSpinLockInit
;
1176 memory
->_socket
= sock
;
1177 if (INVALID_SOCKET
== sock
|| 0 != getsockopt(sock
, SOL_SOCKET
, SO_TYPE
, (void *)&(memory
->_socketType
), (socklen_t
*)&typeSize
)) memory
->_socketType
= 0; // cast for WinSock bad API
1178 memory
->_errorCode
= 0;
1179 memory
->_address
= NULL
;
1180 memory
->_peerAddress
= NULL
;
1181 memory
->_socketSetCount
= 0;
1182 memory
->_source0
= NULL
;
1183 if (INVALID_SOCKET
!= sock
) {
1184 memory
->_runLoops
= CFArrayCreateMutable(allocator
, 0, NULL
);
1186 memory
->_runLoops
= NULL
;
1188 memory
->_callout
= callout
;
1189 memory
->_dataQueue
= NULL
;
1190 memory
->_addressQueue
= NULL
;
1191 memory
->_context
.info
= 0;
1192 memory
->_context
.retain
= 0;
1193 memory
->_context
.release
= 0;
1194 memory
->_context
.copyDescription
= 0;
1195 timerclear(&memory
->_readBufferTimeout
);
1196 memory
->_readBuffer
= NULL
;
1197 memory
->_bytesToBuffer
= 0;
1198 memory
->_bytesToBufferPos
= 0;
1199 memory
->_bytesToBufferReadPos
= 0;
1200 memory
->_atEOF
= false;
1201 memory
->_bufferedReadError
= 0;
1203 if (INVALID_SOCKET
!= sock
) CFDictionaryAddValue(__CFAllSockets
, (void *)(uintptr_t)sock
, memory
);
1204 __CFSpinUnlock(&__CFAllSocketsLock
);
1205 if (NULL
!= context
) {
1206 void *contextInfo
= context
->retain
? (void *)context
->retain(context
->info
) : context
->info
;
1207 __CFSocketLock(memory
);
1208 memory
->_context
.retain
= context
->retain
;
1209 memory
->_context
.release
= context
->release
;
1210 memory
->_context
.copyDescription
= context
->copyDescription
;
1211 memory
->_context
.info
= contextInfo
;
1212 __CFSocketUnlock(memory
);
1217 CFSocketRef
CFSocketCreateWithNative(CFAllocatorRef allocator
, CFSocketNativeHandle sock
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
) {
1218 return _CFSocketCreateWithNative(allocator
, sock
, callBackTypes
, callout
, context
, TRUE
);
1221 void CFSocketInvalidate(CFSocketRef s
) {
1223 UInt32 previousSocketManagerIteration
;
1224 __CFGenericValidateType(s
, __kCFSocketTypeID
);
1225 #if defined(LOG_CFSOCKET)
1226 fprintf(stdout
, "invalidating socket %d with flags 0x%x disabled 0x%x connected 0x%x\n", s
->_socket
, s
->_f
.client
, s
->_f
.disabled
, s
->_f
.connected
);
1227 #endif /* LOG_CFSOCKET */
1229 __CFSpinLock(&__CFAllSocketsLock
);
1231 if (__CFSocketIsValid(s
)) {
1233 CFRunLoopSourceRef source0
;
1234 void *contextInfo
= NULL
;
1235 void (*contextRelease
)(const void *info
) = NULL
;
1236 __CFSocketUnsetValid(s
);
1237 __CFSocketUnsetWriteSignalled(s
);
1238 __CFSocketUnsetReadSignalled(s
);
1239 __CFSpinLock(&__CFActiveSocketsLock
);
1240 idx
= CFArrayGetFirstIndexOfValue(__CFWriteSockets
, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets
)), s
);
1242 CFArrayRemoveValueAtIndex(__CFWriteSockets
, idx
);
1243 __CFSocketClearFDForWrite(s
);
1245 // No need to clear FD's for V1 sources, since we'll just throw the whole event away
1246 idx
= CFArrayGetFirstIndexOfValue(__CFReadSockets
, CFRangeMake(0, CFArrayGetCount(__CFReadSockets
)), s
);
1248 CFArrayRemoveValueAtIndex(__CFReadSockets
, idx
);
1249 __CFSocketClearFDForRead(s
);
1251 previousSocketManagerIteration
= __CFSocketManagerIteration
;
1252 __CFSpinUnlock(&__CFActiveSocketsLock
);
1253 CFDictionaryRemoveValue(__CFAllSockets
, (void *)(uintptr_t)(s
->_socket
));
1254 if ((s
->_f
.client
& kCFSocketCloseOnInvalidate
) != 0) closesocket(s
->_socket
);
1255 s
->_socket
= INVALID_SOCKET
;
1256 if (NULL
!= s
->_peerAddress
) {
1257 CFRelease(s
->_peerAddress
);
1258 s
->_peerAddress
= NULL
;
1260 if (NULL
!= s
->_dataQueue
) {
1261 CFRelease(s
->_dataQueue
);
1262 s
->_dataQueue
= NULL
;
1264 if (NULL
!= s
->_addressQueue
) {
1265 CFRelease(s
->_addressQueue
);
1266 s
->_addressQueue
= NULL
;
1268 s
->_socketSetCount
= 0;
1269 for (idx
= CFArrayGetCount(s
->_runLoops
); idx
--;) {
1270 CFRunLoopWakeUp((CFRunLoopRef
)CFArrayGetValueAtIndex(s
->_runLoops
, idx
));
1272 CFRelease(s
->_runLoops
);
1273 s
->_runLoops
= NULL
;
1274 source0
= s
->_source0
;
1276 contextInfo
= s
->_context
.info
;
1277 contextRelease
= s
->_context
.release
;
1278 s
->_context
.info
= 0;
1279 s
->_context
.retain
= 0;
1280 s
->_context
.release
= 0;
1281 s
->_context
.copyDescription
= 0;
1282 __CFSocketUnlock(s
);
1283 if (NULL
!= contextRelease
) {
1284 contextRelease(contextInfo
);
1286 if (NULL
!= source0
) {
1287 CFRunLoopSourceInvalidate(source0
);
1291 __CFSocketUnlock(s
);
1293 __CFSpinUnlock(&__CFAllSocketsLock
);
1297 Boolean
CFSocketIsValid(CFSocketRef s
) {
1299 __CFGenericValidateType(s
, __kCFSocketTypeID
);
1300 return __CFSocketIsValid(s
);
1303 CFSocketNativeHandle
CFSocketGetNative(CFSocketRef s
) {
1305 __CFGenericValidateType(s
, __kCFSocketTypeID
);
1309 CFDataRef
CFSocketCopyAddress(CFSocketRef s
) {
1311 CFDataRef result
= NULL
;
1312 __CFGenericValidateType(s
, __kCFSocketTypeID
);
1314 __CFSocketEstablishAddress(s
);
1315 if (NULL
!= s
->_address
) {
1316 result
= CFRetain(s
->_address
);
1318 __CFSocketUnlock(s
);
1322 CFDataRef
CFSocketCopyPeerAddress(CFSocketRef s
) {
1324 CFDataRef result
= NULL
;
1325 __CFGenericValidateType(s
, __kCFSocketTypeID
);
1327 __CFSocketEstablishPeerAddress(s
);
1328 if (NULL
!= s
->_peerAddress
) {
1329 result
= CFRetain(s
->_peerAddress
);
1331 __CFSocketUnlock(s
);
1335 void CFSocketGetContext(CFSocketRef s
, CFSocketContext
*context
) {
1337 __CFGenericValidateType(s
, __kCFSocketTypeID
);
1338 CFAssert1(0 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__
);
1339 *context
= s
->_context
;
1342 CFOptionFlags
CFSocketGetSocketFlags(CFSocketRef s
) {
1344 __CFGenericValidateType(s
, __kCFSocketTypeID
);
1345 return s
->_f
.client
;
1348 void CFSocketSetSocketFlags(CFSocketRef s
, CFOptionFlags flags
) {
1350 __CFGenericValidateType(s
, __kCFSocketTypeID
);
1352 #if defined(LOG_CFSOCKET)
1353 fprintf(stdout
, "setting flags for socket %d, from 0x%x to 0x%lx\n", s
->_socket
, s
->_f
.client
, flags
);
1354 #endif /* LOG_CFSOCKET */
1355 s
->_f
.client
= flags
;
1356 __CFSocketUnlock(s
);
1359 void CFSocketDisableCallBacks(CFSocketRef s
, CFOptionFlags callBackTypes
) {
1361 Boolean wakeup
= false;
1362 uint8_t readCallBackType
;
1363 __CFGenericValidateType(s
, __kCFSocketTypeID
);
1365 if (__CFSocketIsValid(s
) && __CFSocketIsScheduled(s
)) {
1366 callBackTypes
&= __CFSocketCallBackTypes(s
);
1367 readCallBackType
= __CFSocketReadCallBackType(s
);
1368 s
->_f
.disabled
|= callBackTypes
;
1369 #if defined(LOG_CFSOCKET)
1370 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
);
1371 #endif /* LOG_CFSOCKET */
1372 __CFSpinLock(&__CFActiveSocketsLock
);
1373 if ((readCallBackType
== kCFSocketAcceptCallBack
) || !__CFSocketIsConnectionOriented(s
)) s
->_f
.connected
= TRUE
;
1374 if (((callBackTypes
& kCFSocketWriteCallBack
) != 0) || (((callBackTypes
& kCFSocketConnectCallBack
) != 0) && !s
->_f
.connected
)) {
1375 if (__CFSocketClearFDForWrite(s
)) {
1376 // do not wake up the socket manager thread if all relevant write callbacks are disabled
1377 CFOptionFlags writeCallBacksAvailable
= __CFSocketCallBackTypes(s
) & (kCFSocketWriteCallBack
| kCFSocketConnectCallBack
);
1378 if (s
->_f
.connected
) writeCallBacksAvailable
&= ~kCFSocketConnectCallBack
;
1379 if ((s
->_f
.disabled
& writeCallBacksAvailable
) != writeCallBacksAvailable
) wakeup
= true;
1382 if (readCallBackType
!= kCFSocketNoCallBack
&& (callBackTypes
& readCallBackType
) != 0) {
1383 if (__CFSocketClearFDForRead(s
)) {
1384 // do not wake up the socket manager thread if callback type is read
1385 if (readCallBackType
!= kCFSocketReadCallBack
) wakeup
= true;
1388 __CFSpinUnlock(&__CFActiveSocketsLock
);
1390 __CFSocketUnlock(s
);
1391 if (wakeup
&& __CFSocketManagerThread
) {
1393 send(__CFWakeupSocketPair
[0], &c
, sizeof(c
), 0);
1397 // "force" means to clear the disabled bits set by DisableCallBacks and always reenable.
1398 // if (!force) we respect those bits, meaning they may stop us from enabling.
1399 // In addition, if !force we assume that the sockets have already been added to the
1400 // __CFReadSockets and __CFWriteSockets arrays. This is true because the callbacks start
1401 // enabled when the CFSocket is created (at which time we enable with force).
1402 // Called with SocketLock held, returns with it released!
1403 void __CFSocketEnableCallBacks(CFSocketRef s
, CFOptionFlags callBackTypes
, Boolean force
, uint8_t wakeupChar
) {
1405 Boolean wakeup
= FALSE
;
1406 if (!callBackTypes
) {
1407 __CFSocketUnlock(s
);
1410 if (__CFSocketIsValid(s
) && __CFSocketIsScheduled(s
)) {
1411 Boolean turnOnWrite
= FALSE
, turnOnConnect
= FALSE
, turnOnRead
= FALSE
;
1412 uint8_t readCallBackType
= __CFSocketReadCallBackType(s
);
1413 callBackTypes
&= __CFSocketCallBackTypes(s
);
1414 if (force
) s
->_f
.disabled
&= ~callBackTypes
;
1415 #if defined(LOG_CFSOCKET)
1416 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
);
1417 #endif /* LOG_CFSOCKET */
1418 /* We will wait for connection only for connection-oriented, non-rendezvous sockets that are not already connected. Mark others as already connected. */
1419 if ((readCallBackType
== kCFSocketAcceptCallBack
) || !__CFSocketIsConnectionOriented(s
)) s
->_f
.connected
= TRUE
;
1421 // First figure out what to turn on
1422 if (s
->_f
.connected
|| (callBackTypes
& kCFSocketConnectCallBack
) == 0) {
1423 // if we want write callbacks and they're not disabled...
1424 if ((callBackTypes
& kCFSocketWriteCallBack
) != 0 && (s
->_f
.disabled
& kCFSocketWriteCallBack
) == 0) turnOnWrite
= TRUE
;
1426 // if we want connect callbacks and they're not disabled...
1427 if ((callBackTypes
& kCFSocketConnectCallBack
) != 0 && (s
->_f
.disabled
& kCFSocketConnectCallBack
) == 0) turnOnConnect
= TRUE
;
1429 // if we want read callbacks and they're not disabled...
1430 if (readCallBackType
!= kCFSocketNoCallBack
&& (callBackTypes
& readCallBackType
) != 0 && (s
->_f
.disabled
& kCFSocketReadCallBack
) == 0) turnOnRead
= TRUE
;
1432 // Now turn on the callbacks we've determined that we want on
1433 if (turnOnRead
|| turnOnWrite
|| turnOnConnect
) {
1434 __CFSpinLock(&__CFActiveSocketsLock
);
1435 if (turnOnWrite
|| turnOnConnect
) {
1437 SInt32 idx
= CFArrayGetFirstIndexOfValue(__CFWriteSockets
, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets
)), s
);
1438 if (kCFNotFound
== idx
) CFArrayAppendValue(__CFWriteSockets
, s
);
1440 if (__CFSocketSetFDForWrite(s
)) wakeup
= true;
1444 SInt32 idx
= CFArrayGetFirstIndexOfValue(__CFReadSockets
, CFRangeMake(0, CFArrayGetCount(__CFReadSockets
)), s
);
1445 if (kCFNotFound
== idx
) CFArrayAppendValue(__CFReadSockets
, s
);
1447 if (__CFSocketSetFDForRead(s
)) wakeup
= true;
1449 if (wakeup
&& NULL
== __CFSocketManagerThread
) __CFSocketManagerThread
= __CFStartSimpleThread(__CFSocketManager
, 0);
1450 __CFSpinUnlock(&__CFActiveSocketsLock
);
1453 __CFSocketUnlock(s
);
1454 if (wakeup
) send(__CFWakeupSocketPair
[0], &wakeupChar
, sizeof(wakeupChar
), 0);
1457 void CFSocketEnableCallBacks(CFSocketRef s
, CFOptionFlags callBackTypes
) {
1459 __CFGenericValidateType(s
, __kCFSocketTypeID
);
1461 __CFSocketEnableCallBacks(s
, callBackTypes
, TRUE
, 'r');
1464 static void __CFSocketSchedule(void *info
, CFRunLoopRef rl
, CFStringRef mode
) {
1465 CFSocketRef s
= info
;
1467 //??? also need to arrange delivery of all pending data
1468 if (__CFSocketIsValid(s
)) {
1469 CFArrayAppendValue(s
->_runLoops
, rl
);
1470 s
->_socketSetCount
++;
1471 // Since the v0 source is listened to on the SocketMgr thread, no matter how many modes it
1472 // is added to we just need to enable it there once (and _socketSetCount gives us a refCount
1473 // to know when we can finally disable it).
1474 if (1 == s
->_socketSetCount
) {
1475 #if defined(LOG_CFSOCKET)
1476 fprintf(stdout
, "scheduling socket %d\n", s
->_socket
);
1477 #endif /* LOG_CFSOCKET */
1478 __CFSocketEnableCallBacks(s
, __CFSocketCallBackTypes(s
), TRUE
, 's'); // unlocks s
1480 __CFSocketUnlock(s
);
1482 __CFSocketUnlock(s
);
1485 static void __CFSocketCancel(void *info
, CFRunLoopRef rl
, CFStringRef mode
) {
1486 CFSocketRef s
= info
;
1489 s
->_socketSetCount
--;
1490 if (0 == s
->_socketSetCount
) {
1491 __CFSpinLock(&__CFActiveSocketsLock
);
1492 idx
= CFArrayGetFirstIndexOfValue(__CFWriteSockets
, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets
)), s
);
1494 CFArrayRemoveValueAtIndex(__CFWriteSockets
, idx
);
1495 __CFSocketClearFDForWrite(s
);
1497 idx
= CFArrayGetFirstIndexOfValue(__CFReadSockets
, CFRangeMake(0, CFArrayGetCount(__CFReadSockets
)), s
);
1499 CFArrayRemoveValueAtIndex(__CFReadSockets
, idx
);
1500 __CFSocketClearFDForRead(s
);
1502 __CFSpinUnlock(&__CFActiveSocketsLock
);
1504 if (NULL
!= s
->_runLoops
) {
1505 idx
= CFArrayGetFirstIndexOfValue(s
->_runLoops
, CFRangeMake(0, CFArrayGetCount(s
->_runLoops
)), rl
);
1506 if (0 <= idx
) CFArrayRemoveValueAtIndex(s
->_runLoops
, idx
);
1508 __CFSocketUnlock(s
);
1511 // Note: must be called with socket lock held, then returns with it released
1512 // Used by both the v0 and v1 RunLoopSource perform routines
1513 static void __CFSocketDoCallback(CFSocketRef s
, CFDataRef data
, CFDataRef address
, CFSocketNativeHandle sock
) {
1514 CFSocketCallBack callout
= NULL
;
1515 void *contextInfo
= NULL
;
1516 SInt32 errorCode
= 0;
1517 Boolean readSignalled
= false, writeSignalled
= false, connectSignalled
= false, calledOut
= false;
1518 uint8_t readCallBackType
, callBackTypes
;
1520 callBackTypes
= __CFSocketCallBackTypes(s
);
1521 readCallBackType
= __CFSocketReadCallBackType(s
);
1522 readSignalled
= __CFSocketIsReadSignalled(s
);
1523 writeSignalled
= __CFSocketIsWriteSignalled(s
);
1524 connectSignalled
= writeSignalled
&& !s
->_f
.connected
;
1525 __CFSocketUnsetReadSignalled(s
);
1526 __CFSocketUnsetWriteSignalled(s
);
1527 callout
= s
->_callout
;
1528 contextInfo
= s
->_context
.info
;
1529 #if defined(LOG_CFSOCKET)
1530 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
);
1531 #endif /* LOG_CFSOCKET */
1532 if (writeSignalled
) {
1533 errorCode
= s
->_errorCode
;
1534 s
->_f
.connected
= TRUE
;
1536 __CFSocketUnlock(s
);
1537 if ((callBackTypes
& kCFSocketConnectCallBack
) != 0) {
1538 if (connectSignalled
&& (!calledOut
|| CFSocketIsValid(s
))) {
1540 #if defined(LOG_CFSOCKET)
1541 fprintf(stdout
, "perform calling out error %ld to socket %d\n", errorCode
, s
->_socket
);
1542 #endif /* LOG_CFSOCKET */
1543 if (callout
) callout(s
, kCFSocketConnectCallBack
, NULL
, &errorCode
, contextInfo
);
1546 #if defined(LOG_CFSOCKET)
1547 fprintf(stdout
, "perform calling out connect to socket %d\n", s
->_socket
);
1548 #endif /* LOG_CFSOCKET */
1549 if (callout
) callout(s
, kCFSocketConnectCallBack
, NULL
, NULL
, contextInfo
);
1554 if (kCFSocketDataCallBack
== readCallBackType
) {
1555 if (NULL
!= data
&& (!calledOut
|| CFSocketIsValid(s
))) {
1556 SInt32 datalen
= CFDataGetLength(data
);
1557 #if defined(LOG_CFSOCKET)
1558 fprintf(stdout
, "perform calling out data of length %ld to socket %d\n", datalen
, s
->_socket
);
1559 #endif /* LOG_CFSOCKET */
1560 if (callout
) callout(s
, kCFSocketDataCallBack
, address
, data
, contextInfo
);
1562 if (0 == datalen
) CFSocketInvalidate(s
);
1564 } else if (kCFSocketAcceptCallBack
== readCallBackType
) {
1565 if (INVALID_SOCKET
!= sock
&& (!calledOut
|| CFSocketIsValid(s
))) {
1566 #if defined(LOG_CFSOCKET)
1567 fprintf(stdout
, "perform calling out accept of socket %d to socket %d\n", sock
, s
->_socket
);
1568 #endif /* LOG_CFSOCKET */
1569 if (callout
) callout(s
, kCFSocketAcceptCallBack
, address
, &sock
, contextInfo
);
1572 } else if (kCFSocketReadCallBack
== readCallBackType
) {
1573 if (readSignalled
&& (!calledOut
|| CFSocketIsValid(s
))) {
1574 #if defined(LOG_CFSOCKET)
1575 fprintf(stdout
, "perform calling out read to socket %d\n", s
->_socket
);
1576 #endif /* LOG_CFSOCKET */
1577 if (callout
) callout(s
, kCFSocketReadCallBack
, NULL
, NULL
, contextInfo
);
1581 if ((callBackTypes
& kCFSocketWriteCallBack
) != 0) {
1582 if (writeSignalled
&& !errorCode
&& (!calledOut
|| CFSocketIsValid(s
))) {
1583 #if defined(LOG_CFSOCKET)
1584 fprintf(stdout
, "perform calling out write to socket %d\n", s
->_socket
);
1585 #endif /* LOG_CFSOCKET */
1586 if (callout
) callout(s
, kCFSocketWriteCallBack
, NULL
, NULL
, contextInfo
);
1592 static void __CFSocketPerformV0(void *info
) {
1593 CFSocketRef s
= info
;
1594 CFDataRef data
= NULL
;
1595 CFDataRef address
= NULL
;
1596 CFSocketNativeHandle sock
= INVALID_SOCKET
;
1597 uint8_t readCallBackType
, callBackTypes
;
1598 CFRunLoopRef rl
= NULL
;
1601 if (!__CFSocketIsValid(s
)) {
1602 __CFSocketUnlock(s
);
1605 callBackTypes
= __CFSocketCallBackTypes(s
);
1606 readCallBackType
= __CFSocketReadCallBackType(s
);
1607 CFOptionFlags callBacksSignalled
= 0;
1608 if (__CFSocketIsReadSignalled(s
)) callBacksSignalled
|= readCallBackType
;
1609 if (__CFSocketIsWriteSignalled(s
)) callBacksSignalled
|= kCFSocketWriteCallBack
;
1611 if (kCFSocketDataCallBack
== readCallBackType
) {
1612 if (NULL
!= s
->_dataQueue
&& 0 < CFArrayGetCount(s
->_dataQueue
)) {
1613 data
= CFArrayGetValueAtIndex(s
->_dataQueue
, 0);
1615 CFArrayRemoveValueAtIndex(s
->_dataQueue
, 0);
1616 address
= CFArrayGetValueAtIndex(s
->_addressQueue
, 0);
1618 CFArrayRemoveValueAtIndex(s
->_addressQueue
, 0);
1620 } else if (kCFSocketAcceptCallBack
== readCallBackType
) {
1621 if (NULL
!= s
->_dataQueue
&& 0 < CFArrayGetCount(s
->_dataQueue
)) {
1622 sock
= (CFSocketNativeHandle
)(uintptr_t)CFArrayGetValueAtIndex(s
->_dataQueue
, 0);
1623 CFArrayRemoveValueAtIndex(s
->_dataQueue
, 0);
1624 address
= CFArrayGetValueAtIndex(s
->_addressQueue
, 0);
1626 CFArrayRemoveValueAtIndex(s
->_addressQueue
, 0);
1630 __CFSocketDoCallback(s
, data
, address
, sock
); // does __CFSocketUnlock(s)
1631 if (NULL
!= data
) CFRelease(data
);
1632 if (NULL
!= address
) CFRelease(address
);
1635 if (__CFSocketIsValid(s
) && kCFSocketNoCallBack
!= readCallBackType
) {
1636 // if there's still more data, we want to wake back up right away
1637 if ((kCFSocketDataCallBack
== readCallBackType
|| kCFSocketAcceptCallBack
== readCallBackType
) && NULL
!= s
->_dataQueue
&& 0 < CFArrayGetCount(s
->_dataQueue
)) {
1638 CFRunLoopSourceSignal(s
->_source0
);
1639 #if defined(LOG_CFSOCKET)
1640 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
);
1641 #endif /* LOG_CFSOCKET */
1642 rl
= __CFSocketCopyRunLoopToWakeUp(s
);
1645 // Only reenable callbacks that are auto-reenabled
1646 __CFSocketEnableCallBacks(s
, callBacksSignalled
& s
->_f
.client
, FALSE
, 'p'); // unlocks s
1649 CFRunLoopWakeUp(rl
);
1654 CFRunLoopSourceRef
CFSocketCreateRunLoopSource(CFAllocatorRef allocator
, CFSocketRef s
, CFIndex order
) {
1656 CFRunLoopSourceRef result
= NULL
;
1657 __CFGenericValidateType(s
, __kCFSocketTypeID
);
1659 if (__CFSocketIsValid(s
)) {
1660 if (NULL
== s
->_source0
) {
1661 CFRunLoopSourceContext context
;
1662 context
.version
= 0;
1664 context
.retain
= CFRetain
;
1665 context
.release
= CFRelease
;
1666 context
.copyDescription
= CFCopyDescription
;
1667 context
.equal
= CFEqual
;
1668 context
.hash
= CFHash
;
1669 context
.schedule
= __CFSocketSchedule
;
1670 context
.cancel
= __CFSocketCancel
;
1671 context
.perform
= __CFSocketPerformV0
;
1672 s
->_source0
= CFRunLoopSourceCreate(allocator
, order
, &context
);
1674 CFRetain(s
->_source0
); /* This retain is for the receiver */
1675 result
= s
->_source0
;
1677 __CFSocketUnlock(s
);
1681 #endif /* NEW_SOCKET */
1683 static CFSpinLock_t __CFSocketWriteLock_
= CFSpinLockInit
;
1684 //#warning can only send on one socket at a time now
1686 CF_INLINE
void __CFSocketWriteLock(CFSocketRef s
) {
1687 __CFSpinLock(& __CFSocketWriteLock_
);
1690 CF_INLINE
void __CFSocketWriteUnlock(CFSocketRef s
) {
1691 __CFSpinUnlock(& __CFSocketWriteLock_
);
1694 //??? need timeout, error handling, retries
1695 CFSocketError
CFSocketSendData(CFSocketRef s
, CFDataRef address
, CFDataRef data
, CFTimeInterval timeout
) {
1697 const uint8_t *dataptr
, *addrptr
= NULL
;
1698 SInt32 datalen
, addrlen
= 0, size
= 0;
1699 CFSocketNativeHandle sock
= INVALID_SOCKET
;
1701 __CFGenericValidateType(s
, CFSocketGetTypeID());
1703 addrptr
= CFDataGetBytePtr(address
);
1704 addrlen
= CFDataGetLength(address
);
1706 dataptr
= CFDataGetBytePtr(data
);
1707 datalen
= CFDataGetLength(data
);
1708 if (CFSocketIsValid(s
)) sock
= CFSocketGetNative(s
);
1709 if (INVALID_SOCKET
!= sock
) {
1711 __CFSocketWriteLock(s
);
1712 tv
.tv_sec
= (0 >= timeout
|| INT_MAX
<= timeout
) ? INT_MAX
: (int)(float)floor(timeout
);
1713 tv
.tv_usec
= (int)((timeout
- floor(timeout
)) * 1.0E6
);
1714 setsockopt(sock
, SOL_SOCKET
, SO_SNDTIMEO
, (void *)&tv
, sizeof(tv
)); // cast for WinSock bad API
1715 if (NULL
!= addrptr
&& 0 < addrlen
) {
1716 size
= sendto(sock
, dataptr
, datalen
, 0, (struct sockaddr
*)addrptr
, addrlen
);
1718 size
= send(sock
, dataptr
, datalen
, 0);
1720 #if defined(LOG_CFSOCKET)
1721 fprintf(stdout
, "wrote %ld bytes to socket %d\n", size
, sock
);
1722 #endif /* LOG_CFSOCKET */
1723 __CFSocketWriteUnlock(s
);
1726 return (size
> 0) ? kCFSocketSuccess
: kCFSocketError
;
1729 CFSocketError
CFSocketSetAddress(CFSocketRef s
, CFDataRef address
) {
1731 const uint8_t *name
;
1732 SInt32 namelen
, result
= 0;
1733 __CFGenericValidateType(s
, CFSocketGetTypeID());
1734 if (NULL
== address
) return -1;
1735 if (!CFSocketIsValid(s
)) return 0;
1736 name
= CFDataGetBytePtr(address
);
1737 namelen
= CFDataGetLength(address
);
1738 if (!name
|| namelen
<= 0) return 0;
1739 CFSocketNativeHandle sock
= CFSocketGetNative(s
);
1740 result
= bind(sock
, (struct sockaddr
*)name
, namelen
);
1744 //??? should return errno
1748 CFSocketError
CFSocketConnectToAddress(CFSocketRef s
, CFDataRef address
, CFTimeInterval timeout
) {
1750 //??? need error handling, retries
1751 const uint8_t *name
;
1752 SInt32 namelen
, result
= -1, connect_err
= 0, select_err
= 0;
1753 UInt32 yes
= 1, no
= 0;
1754 Boolean wasBlocking
= true;
1756 __CFGenericValidateType(s
, CFSocketGetTypeID());
1757 if (!CFSocketIsValid(s
)) return 0;
1758 name
= CFDataGetBytePtr(address
);
1759 namelen
= CFDataGetLength(address
);
1760 if (!name
|| namelen
<= 0) return 0;
1761 CFSocketNativeHandle sock
= CFSocketGetNative(s
);
1763 SInt32 flags
= fcntl(sock
, F_GETFL
, 0);
1764 if (flags
>= 0) wasBlocking
= ((flags
& O_NONBLOCK
) == 0);
1765 if (wasBlocking
&& (timeout
> 0.0 || timeout
< 0.0)) ioctlsocket(sock
, FIONBIO
, &yes
);
1766 result
= connect(sock
, (struct sockaddr
*)name
, namelen
);
1768 connect_err
= __CFSocketLastError();
1770 #if defined(LOG_CFSOCKET)
1771 fprintf(stdout
, "connection attempt returns %ld error %ld on socket %d (flags 0x%lx blocking %d)\n", result
, connect_err
, sock
, flags
, wasBlocking
);
1772 #endif /* LOG_CFSOCKET */
1773 if (EINPROGRESS
== connect_err
&& timeout
>= 0.0) {
1774 /* select on socket */
1776 int error_size
= sizeof(select_err
);
1778 CFMutableDataRef fds
= CFDataCreateMutable(kCFAllocatorSystemDefault
, 0);
1779 __CFSocketFdSet(sock
, fds
);
1780 tv
.tv_sec
= (0 >= timeout
|| INT_MAX
<= timeout
) ? INT_MAX
: (int)(float)floor(timeout
);
1781 tv
.tv_usec
= (int)((timeout
- floor(timeout
)) * 1.0E6
);
1782 nrfds
= select(__CFSocketFdGetSize(fds
), NULL
, (fd_set
*)CFDataGetMutableBytePtr(fds
), NULL
, &tv
);
1784 select_err
= __CFSocketLastError();
1786 } else if (nrfds
== 0) {
1789 if (0 != getsockopt(sock
, SOL_SOCKET
, SO_ERROR
, (void *)&select_err
, (socklen_t
*)&error_size
)) select_err
= 0;
1790 result
= (select_err
== 0) ? 0 : -1;
1793 #if defined(LOG_CFSOCKET)
1794 fprintf(stdout
, "timed connection attempt %s on socket %d, result %ld, select returns %ld error %ld\n", (result
== 0) ? "succeeds" : "fails", sock
, result
, nrfds
, select_err
);
1795 #endif /* LOG_CFSOCKET */
1797 if (wasBlocking
&& (timeout
> 0.0 || timeout
< 0.0)) ioctlsocket(sock
, FIONBIO
, &no
);
1798 if (EINPROGRESS
== connect_err
&& timeout
< 0.0) {
1800 #if defined(LOG_CFSOCKET)
1801 fprintf(stdout
, "connection attempt continues in background on socket %d\n", sock
);
1802 #endif /* LOG_CFSOCKET */
1805 //??? should return errno
1809 CFSocketRef
CFSocketCreate(CFAllocatorRef allocator
, SInt32 protocolFamily
, SInt32 socketType
, SInt32 protocol
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
) {
1811 CFSocketNativeHandle sock
= INVALID_SOCKET
;
1812 CFSocketRef s
= NULL
;
1813 if (0 >= protocolFamily
) protocolFamily
= PF_INET
;
1814 if (PF_INET
== protocolFamily
) {
1815 if (0 >= socketType
) socketType
= SOCK_STREAM
;
1816 if (0 >= protocol
&& SOCK_STREAM
== socketType
) protocol
= IPPROTO_TCP
;
1817 if (0 >= protocol
&& SOCK_DGRAM
== socketType
) protocol
= IPPROTO_UDP
;
1819 if (PF_LOCAL
== protocolFamily
&& 0 >= socketType
) socketType
= SOCK_STREAM
;
1820 sock
= socket(protocolFamily
, socketType
, protocol
);
1821 if (INVALID_SOCKET
!= sock
) {
1822 s
= _CFSocketCreateWithNative(allocator
, sock
, callBackTypes
, callout
, context
, FALSE
);
1827 CFSocketRef
CFSocketCreateWithSocketSignature(CFAllocatorRef allocator
, const CFSocketSignature
*signature
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
) {
1829 CFSocketRef s
= CFSocketCreate(allocator
, signature
->protocolFamily
, signature
->socketType
, signature
->protocol
, callBackTypes
, callout
, context
);
1830 if (NULL
!= s
&& (!CFSocketIsValid(s
) || kCFSocketSuccess
!= CFSocketSetAddress(s
, signature
->address
))) {
1831 CFSocketInvalidate(s
);
1838 CFSocketRef
CFSocketCreateConnectedToSocketSignature(CFAllocatorRef allocator
, const CFSocketSignature
*signature
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
, CFTimeInterval timeout
) {
1840 CFSocketRef s
= CFSocketCreate(allocator
, signature
->protocolFamily
, signature
->socketType
, signature
->protocol
, callBackTypes
, callout
, context
);
1841 if (NULL
!= s
&& (!CFSocketIsValid(s
) || kCFSocketSuccess
!= CFSocketConnectToAddress(s
, signature
->address
, timeout
))) {
1842 CFSocketInvalidate(s
);
1850 CFSocketError
*error
;
1851 CFPropertyListRef
*value
;
1853 } __CFSocketNameRegistryResponse
;
1855 static void __CFSocketHandleNameRegistryReply(CFSocketRef s
, CFSocketCallBackType type
, CFDataRef address
, const void *data
, void *info
) {
1856 CFDataRef replyData
= (CFDataRef
)data
;
1857 __CFSocketNameRegistryResponse
*response
= (__CFSocketNameRegistryResponse
*)info
;
1858 CFDictionaryRef replyDictionary
= NULL
;
1859 CFPropertyListRef value
;
1860 replyDictionary
= CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault
, replyData
, kCFPropertyListImmutable
, NULL
);
1861 if (NULL
!= response
->error
) *(response
->error
) = kCFSocketError
;
1862 if (NULL
!= replyDictionary
) {
1863 if (CFGetTypeID((CFTypeRef
)replyDictionary
) == CFDictionaryGetTypeID() && NULL
!= (value
= CFDictionaryGetValue(replyDictionary
, kCFSocketResultKey
))) {
1864 if (NULL
!= response
->error
) *(response
->error
) = kCFSocketSuccess
;
1865 if (NULL
!= response
->value
) *(response
->value
) = CFRetain(value
);
1866 if (NULL
!= response
->address
) *(response
->address
) = address
? CFDataCreateCopy(kCFAllocatorSystemDefault
, address
) : NULL
;
1868 CFRelease(replyDictionary
);
1870 CFSocketInvalidate(s
);
1873 static void __CFSocketSendNameRegistryRequest(CFSocketSignature
*signature
, CFDictionaryRef requestDictionary
, __CFSocketNameRegistryResponse
*response
, CFTimeInterval timeout
) {
1874 CFDataRef requestData
= NULL
;
1875 CFSocketContext context
= {0, response
, NULL
, NULL
, NULL
};
1876 CFSocketRef s
= NULL
;
1877 CFRunLoopSourceRef source
= NULL
;
1878 if (NULL
!= response
->error
) *(response
->error
) = kCFSocketError
;
1879 requestData
= CFPropertyListCreateXMLData(kCFAllocatorSystemDefault
, requestDictionary
);
1880 if (NULL
!= requestData
) {
1881 if (NULL
!= response
->error
) *(response
->error
) = kCFSocketTimeout
;
1882 s
= CFSocketCreateConnectedToSocketSignature(kCFAllocatorSystemDefault
, signature
, kCFSocketDataCallBack
, __CFSocketHandleNameRegistryReply
, &context
, timeout
);
1884 if (kCFSocketSuccess
== CFSocketSendData(s
, NULL
, requestData
, timeout
)) {
1885 source
= CFSocketCreateRunLoopSource(kCFAllocatorSystemDefault
, s
, 0);
1886 CFRunLoopAddSource(CFRunLoopGetCurrent(), source
, __kCFSocketRegistryRequestRunLoopMode
);
1887 CFRunLoopRunInMode(__kCFSocketRegistryRequestRunLoopMode
, timeout
, false);
1890 CFSocketInvalidate(s
);
1893 CFRelease(requestData
);
1897 static void __CFSocketValidateSignature(const CFSocketSignature
*providedSignature
, CFSocketSignature
*signature
, uint16_t defaultPortNumber
) {
1898 struct sockaddr_in sain
, *sainp
;
1899 memset(&sain
, 0, sizeof(sain
));
1900 sain
.sin_len
= sizeof(sain
);
1901 sain
.sin_family
= AF_INET
;
1902 sain
.sin_port
= htons(__CFSocketDefaultNameRegistryPortNumber
);
1903 sain
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
1904 if (NULL
== providedSignature
) {
1905 signature
->protocolFamily
= PF_INET
;
1906 signature
->socketType
= SOCK_STREAM
;
1907 signature
->protocol
= IPPROTO_TCP
;
1908 signature
->address
= CFDataCreate(kCFAllocatorSystemDefault
, (uint8_t *)&sain
, sizeof(sain
));
1910 signature
->protocolFamily
= providedSignature
->protocolFamily
;
1911 signature
->socketType
= providedSignature
->socketType
;
1912 signature
->protocol
= providedSignature
->protocol
;
1913 if (0 >= signature
->protocolFamily
) signature
->protocolFamily
= PF_INET
;
1914 if (PF_INET
== signature
->protocolFamily
) {
1915 if (0 >= signature
->socketType
) signature
->socketType
= SOCK_STREAM
;
1916 if (0 >= signature
->protocol
&& SOCK_STREAM
== signature
->socketType
) signature
->protocol
= IPPROTO_TCP
;
1917 if (0 >= signature
->protocol
&& SOCK_DGRAM
== signature
->socketType
) signature
->protocol
= IPPROTO_UDP
;
1919 if (NULL
== providedSignature
->address
) {
1920 signature
->address
= CFDataCreate(kCFAllocatorSystemDefault
, (uint8_t *)&sain
, sizeof(sain
));
1922 sainp
= (struct sockaddr_in
*)CFDataGetBytePtr(providedSignature
->address
);
1923 if ((int)sizeof(struct sockaddr_in
) <= CFDataGetLength(providedSignature
->address
) && (AF_INET
== sainp
->sin_family
|| 0 == sainp
->sin_family
)) {
1924 sain
.sin_len
= sizeof(sain
);
1925 sain
.sin_family
= AF_INET
;
1926 sain
.sin_port
= sainp
->sin_port
;
1927 if (0 == sain
.sin_port
) sain
.sin_port
= htons(defaultPortNumber
);
1928 sain
.sin_addr
.s_addr
= sainp
->sin_addr
.s_addr
;
1929 if (htonl(INADDR_ANY
) == sain
.sin_addr
.s_addr
) sain
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
1930 signature
->address
= CFDataCreate(kCFAllocatorSystemDefault
, (uint8_t *)&sain
, sizeof(sain
));
1932 signature
->address
= CFRetain(providedSignature
->address
);
1938 CFSocketError
CFSocketRegisterValue(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
, CFPropertyListRef value
) {
1939 CFSocketSignature signature
;
1940 CFMutableDictionaryRef dictionary
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 3, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1941 CFSocketError retval
= kCFSocketError
;
1942 __CFSocketNameRegistryResponse response
= {&retval
, NULL
, NULL
};
1943 CFDictionaryAddValue(dictionary
, kCFSocketCommandKey
, kCFSocketRegisterCommand
);
1944 CFDictionaryAddValue(dictionary
, kCFSocketNameKey
, name
);
1945 if (NULL
!= value
) CFDictionaryAddValue(dictionary
, kCFSocketValueKey
, value
);
1946 __CFSocketValidateSignature(nameServerSignature
, &signature
, __CFSocketDefaultNameRegistryPortNumber
);
1947 __CFSocketSendNameRegistryRequest(&signature
, dictionary
, &response
, timeout
);
1948 CFRelease(dictionary
);
1949 CFRelease(signature
.address
);
1953 CFSocketError
CFSocketCopyRegisteredValue(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
, CFPropertyListRef
*value
, CFDataRef
*serverAddress
) {
1954 CFSocketSignature signature
;
1955 CFMutableDictionaryRef dictionary
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 2, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1956 CFSocketError retval
= kCFSocketError
;
1957 __CFSocketNameRegistryResponse response
= {&retval
, value
, serverAddress
};
1958 CFDictionaryAddValue(dictionary
, kCFSocketCommandKey
, kCFSocketRetrieveCommand
);
1959 CFDictionaryAddValue(dictionary
, kCFSocketNameKey
, name
);
1960 __CFSocketValidateSignature(nameServerSignature
, &signature
, __CFSocketDefaultNameRegistryPortNumber
);
1961 __CFSocketSendNameRegistryRequest(&signature
, dictionary
, &response
, timeout
);
1962 CFRelease(dictionary
);
1963 CFRelease(signature
.address
);
1967 CFSocketError
CFSocketRegisterSocketSignature(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
, const CFSocketSignature
*signature
) {
1968 CFSocketSignature validatedSignature
;
1969 CFMutableDataRef data
= NULL
;
1970 CFSocketError retval
;
1973 if (NULL
== signature
) {
1974 retval
= CFSocketUnregister(nameServerSignature
, timeout
, name
);
1976 __CFSocketValidateSignature(signature
, &validatedSignature
, 0);
1977 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
) {
1978 retval
= kCFSocketError
;
1980 data
= CFDataCreateMutable(kCFAllocatorSystemDefault
, sizeof(bytes
) + length
);
1981 bytes
[0] = validatedSignature
.protocolFamily
;
1982 bytes
[1] = validatedSignature
.socketType
;
1983 bytes
[2] = validatedSignature
.protocol
;
1985 CFDataAppendBytes(data
, bytes
, sizeof(bytes
));
1986 CFDataAppendBytes(data
, CFDataGetBytePtr(validatedSignature
.address
), length
);
1987 retval
= CFSocketRegisterValue(nameServerSignature
, timeout
, name
, data
);
1990 CFRelease(validatedSignature
.address
);
1995 CFSocketError
CFSocketCopyRegisteredSocketSignature(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
, CFSocketSignature
*signature
, CFDataRef
*nameServerAddress
) {
1996 CFDataRef data
= NULL
;
1997 CFSocketSignature returnedSignature
;
1998 const uint8_t *ptr
= NULL
, *aptr
= NULL
;
2001 CFDataRef serverAddress
= NULL
;
2002 CFSocketError retval
= CFSocketCopyRegisteredValue(nameServerSignature
, timeout
, name
, (CFPropertyListRef
*)&data
, &serverAddress
);
2003 if (NULL
== data
|| CFGetTypeID(data
) != CFDataGetTypeID() || NULL
== (ptr
= CFDataGetBytePtr(data
)) || (length
= CFDataGetLength(data
)) < 4) retval
= kCFSocketError
;
2004 if (kCFSocketSuccess
== retval
&& NULL
!= signature
) {
2005 returnedSignature
.protocolFamily
= (SInt32
)*ptr
++;
2006 returnedSignature
.socketType
= (SInt32
)*ptr
++;
2007 returnedSignature
.protocol
= (SInt32
)*ptr
++;
2009 returnedSignature
.address
= CFDataCreate(kCFAllocatorSystemDefault
, ptr
, length
- 4);
2010 __CFSocketValidateSignature(&returnedSignature
, signature
, 0);
2011 CFRelease(returnedSignature
.address
);
2012 ptr
= CFDataGetBytePtr(signature
->address
);
2013 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
) {
2014 CFMutableDataRef address
= CFDataCreateMutableCopy(kCFAllocatorSystemDefault
, CFDataGetLength(signature
->address
), signature
->address
);
2015 mptr
= CFDataGetMutableBytePtr(address
);
2016 ((struct sockaddr_in
*)mptr
)->sin_addr
= ((struct sockaddr_in
*)aptr
)->sin_addr
;
2017 CFRelease(signature
->address
);
2018 signature
->address
= address
;
2020 if (NULL
!= nameServerAddress
) *nameServerAddress
= serverAddress
? CFRetain(serverAddress
) : NULL
;
2022 if (NULL
!= data
) CFRelease(data
);
2023 if (NULL
!= serverAddress
) CFRelease(serverAddress
);
2027 CFSocketError
CFSocketUnregister(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
) {
2028 return CFSocketRegisterValue(nameServerSignature
, timeout
, name
, NULL
);
2031 CF_EXPORT
void CFSocketSetDefaultNameRegistryPortNumber(uint16_t port
) {
2032 __CFSocketDefaultNameRegistryPortNumber
= port
;
2035 CF_EXPORT
uint16_t CFSocketGetDefaultNameRegistryPortNumber(void) {
2036 return __CFSocketDefaultNameRegistryPortNumber
;