2 * Copyright (c) 2009 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 Copyright (c) 1999-2009, Apple Inc. All rights reserved.
26 Responsibility: Christopher Kane
34 #include <CoreFoundation/CFSocket.h>
35 #include "CFInternal.h"
36 #include <dispatch/dispatch.h>
37 #include <netinet/in.h>
38 #include <sys/sysctl.h>
39 #include <sys/socket.h>
40 #include <sys/ioctl.h>
45 extern void _CFRunLoopSourceWakeUpRunLoops(CFRunLoopSourceRef rls
);
47 #define INVALID_SOCKET (CFSocketNativeHandle)(-1)
48 #define MAX_SOCKADDR_LEN 256
51 DISPATCH_HELPER_FUNCTIONS(sock
, CFSocket
)
55 kCFSocketStateReady
= 0,
56 kCFSocketStateInvalidating
= 1,
57 kCFSocketStateInvalid
= 2,
58 kCFSocketStateDeallocating
= 3
61 struct __shared_blob
{
62 dispatch_source_t _rdsrc
;
63 dispatch_source_t _wrsrc
;
64 CFRunLoopSourceRef _source
;
65 CFSocketNativeHandle _socket
;
72 struct __shared_blob
*_shared
; /* non-NULL when valid, NULL when invalid */
74 uint8_t _state
:2; /* mutable, not written safely */
75 uint8_t _isSaneFD
:1; /* immutable */
76 uint8_t _connOriented
:1; /* immutable */
77 uint8_t _wantConnect
:1; /* immutable */
78 uint8_t _wantWrite
:1; /* immutable */
79 uint8_t _wantReadType
:2; /* immutable */
83 uint8_t _rsuspended
:1;
84 uint8_t _wsuspended
:1;
89 uint8_t _reenableRead
:1;
90 uint8_t _readDisabled
:1;
91 uint8_t _reeanbleWrite
:1;
92 uint8_t _writeDisabled
:1;
93 uint8_t _connectDisabled
:1;
95 uint8_t _leaveErrors
:1;
96 uint8_t _closeOnInvalidate
:1;
98 int32_t _runLoopCounter
;
100 CFDataRef _address
; /* immutable, once created */
101 CFDataRef _peerAddress
; /* immutable, once created */
102 CFSocketCallBack _callout
; /* immutable */
103 CFSocketContext _context
; /* immutable */
107 CF_INLINE Boolean
__CFSocketIsValid(CFSocketRef sock
) {
108 return kCFSocketStateReady
== sock
->_state
;
111 static CFStringRef
__CFSocketCopyDescription(CFTypeRef cf
) {
112 CFSocketRef sock
= (CFSocketRef
)cf
;
113 CFStringRef contextDesc
= NULL
;
114 if (NULL
!= sock
->_context
.info
&& NULL
!= sock
->_context
.copyDescription
) {
115 contextDesc
= sock
->_context
.copyDescription(sock
->_context
.info
);
117 if (NULL
== contextDesc
) {
118 contextDesc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFSocket context %p>"), sock
->_context
.info
);
121 void *addr
= sock
->_callout
;
122 const char *name
= (dladdr(addr
, &info
) && info
.dli_saddr
== addr
&& info
.dli_sname
) ? info
.dli_sname
: "???";
124 ioctl(sock
->_shared
? sock
->_shared
->_socket
: -1, FIONREAD
, &avail
);
125 CFStringRef result
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR(
126 "<CFSocket %p [%p]>{valid = %s, socket = %d, "
127 "want connect = %s, connect disabled = %s, "
128 "want write = %s, reenable write = %s, write disabled = %s, "
129 "want read = %s, reenable read = %s, read disabled = %s, "
130 "leave errors = %s, close on invalidate = %s, connected = %s, "
131 "last error code = %d, bytes available for read = %d, "
132 "source = %p, callout = %s (%p), context = %@}"),
133 cf
, CFGetAllocator(sock
), __CFSocketIsValid(sock
) ? "Yes" : "No", sock
->_shared
? sock
->_shared
->_socket
: -1,
134 sock
->_wantConnect
? "Yes" : "No", sock
->_connectDisabled
? "Yes" : "No",
135 sock
->_wantWrite
? "Yes" : "No", sock
->_reeanbleWrite
? "Yes" : "No", sock
->_writeDisabled
? "Yes" : "No",
136 sock
->_wantReadType
? "Yes" : "No", sock
->_reenableRead
? "Yes" : "No", sock
->_readDisabled
? "Yes" : "No",
137 sock
->_leaveErrors
? "Yes" : "No", sock
->_closeOnInvalidate
? "Yes" : "No", sock
->_connected
? "Yes" : "No",
139 sock
->_shared
? sock
->_shared
->_source
: NULL
, name
, addr
, contextDesc
);
140 if (NULL
!= contextDesc
) {
141 CFRelease(contextDesc
);
146 static void __CFSocketDeallocate(CFTypeRef cf
) {
147 CHECK_FOR_FORK_RET();
148 CFSocketRef sock
= (CFSocketRef
)cf
;
149 /* Since CFSockets are cached, we can only get here sometime after being invalidated */
150 sock
->_state
= kCFSocketStateDeallocating
;
151 if (sock
->_peerAddress
) {
152 CFRelease(sock
->_peerAddress
);
153 sock
->_peerAddress
= NULL
;
155 if (sock
->_address
) {
156 CFRelease(sock
->_address
);
157 sock
->_address
= NULL
;
161 static CFTypeID __kCFSocketTypeID
= _kCFRuntimeNotATypeID
;
163 static const CFRuntimeClass __CFSocketClass
= {
168 __CFSocketDeallocate
,
172 __CFSocketCopyDescription
175 static CFMutableArrayRef __CFAllSockets
= NULL
;
177 CFTypeID
CFSocketGetTypeID(void) {
178 if (_kCFRuntimeNotATypeID
== __kCFSocketTypeID
) {
179 __kCFSocketTypeID
= _CFRuntimeRegisterClass(&__CFSocketClass
);
180 __CFAllSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
182 int ret1
= getrlimit(RLIMIT_NOFILE
, &lim1
);
183 int mib
[] = {CTL_KERN
, KERN_MAXFILESPERPROC
};
185 size_t len
= sizeof(int);
186 int ret0
= sysctl(mib
, 2, &maxfd
, &len
, NULL
, 0);
187 if (0 == ret0
&& 0 == ret1
&& lim1
.rlim_max
< maxfd
) maxfd
= lim1
.rlim_max
;
188 if (0 == ret1
&& lim1
.rlim_cur
< maxfd
) {
189 struct rlimit lim2
= lim1
;
190 lim2
.rlim_cur
+= 2304;
191 if (maxfd
< lim2
.rlim_cur
) lim2
.rlim_cur
= maxfd
;
192 setrlimit(RLIMIT_NOFILE
, &lim2
);
193 // we try, but do not go to extraordinary measures
196 return __kCFSocketTypeID
;
199 CFSocketRef
CFSocketCreateWithNative(CFAllocatorRef allocator
, CFSocketNativeHandle ufd
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
) {
200 CHECK_FOR_FORK_RET(NULL
);
202 CFSocketGetTypeID(); // cause initialization if necessary
205 int ret
= fstat(ufd
, &statbuf
);
206 if (ret
< 0) ufd
= INVALID_SOCKET
;
208 Boolean sane
= false;
209 if (INVALID_SOCKET
!= ufd
) {
210 uint32_t type
= (statbuf
.st_mode
& S_IFMT
);
211 sane
= (S_IFSOCK
== type
) || (S_IFIFO
== type
) || (S_IFCHR
== type
);
213 CFLog(kCFLogLevelWarning
, CFSTR("*** CFSocketCreateWithNative(): creating CFSocket with silly fd type (%07o) -- may or may not work"), type
);
217 if (INVALID_SOCKET
!= ufd
) {
218 Boolean canHandle
= false;
219 int tmp_kq
= kqueue();
222 EV_SET(&ev
[0], ufd
, EVFILT_READ
, EV_ADD
, 0, 0, 0);
223 EV_SET(&ev
[1], ufd
, EVFILT_WRITE
, EV_ADD
, 0, 0, 0);
224 int ret
= kevent(tmp_kq
, ev
, 2, NULL
, 0, NULL
);
225 canHandle
= (0 <= ret
); // if kevent(ADD) succeeds, can handle
228 if (0 && !canHandle
) {
229 CFLog(kCFLogLevelWarning
, CFSTR("*** CFSocketCreateWithNative(): creating CFSocket with unsupported fd type -- may or may not work"));
233 if (INVALID_SOCKET
== ufd
) {
234 // Historically, bad ufd was allowed, but gave an uncached and already-invalid CFSocketRef
235 SInt32 size
= sizeof(struct __CFSocket
) - sizeof(CFRuntimeBase
);
236 CFSocketRef memory
= (CFSocketRef
)_CFRuntimeCreateInstance(allocator
, CFSocketGetTypeID(), size
, NULL
);
237 if (NULL
== memory
) {
240 memory
->_callout
= callout
;
241 memory
->_state
= kCFSocketStateInvalid
;
245 __block CFSocketRef sock
= NULL
;
246 dispatch_sync(__sockQueue(), ^{
247 for (CFIndex idx
= 0, cnt
= CFArrayGetCount(__CFAllSockets
); idx
< cnt
; idx
++) {
248 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFAllSockets
, idx
);
249 if (s
->_shared
->_socket
== ufd
) {
256 SInt32 size
= sizeof(struct __CFSocket
) - sizeof(CFRuntimeBase
);
257 CFSocketRef memory
= (CFSocketRef
)_CFRuntimeCreateInstance(allocator
, CFSocketGetTypeID(), size
, NULL
);
258 if (NULL
== memory
) {
263 if (INVALID_SOCKET
!= ufd
) {
264 socklen_t typeSize
= sizeof(socketType
);
265 int ret
= getsockopt(ufd
, SOL_SOCKET
, SO_TYPE
, (void *)&socketType
, (socklen_t
*)&typeSize
);
266 if (ret
< 0) socketType
= 0;
269 memory
->_rsuspended
= true;
270 memory
->_wsuspended
= true;
271 memory
->_readable
= false;
272 memory
->_writeable
= false;
274 memory
->_isSaneFD
= sane
? 1 : 0;
275 memory
->_wantReadType
= (callBackTypes
& 0x3);
276 memory
->_reenableRead
= memory
->_wantReadType
? true : false;
277 memory
->_readDisabled
= false;
278 memory
->_wantWrite
= (callBackTypes
& kCFSocketWriteCallBack
) ? true : false;
279 memory
->_reeanbleWrite
= false;
280 memory
->_writeDisabled
= false;
281 memory
->_wantConnect
= (callBackTypes
& kCFSocketConnectCallBack
) ? true : false;
282 memory
->_connectDisabled
= false;
283 memory
->_leaveErrors
= false;
284 memory
->_closeOnInvalidate
= true;
285 memory
->_connOriented
= (SOCK_STREAM
== socketType
|| SOCK_SEQPACKET
== socketType
);
286 memory
->_connected
= (memory
->_wantReadType
== kCFSocketAcceptCallBack
|| !memory
->_connOriented
) ? true : false;
289 memory
->_runLoopCounter
= 0;
290 memory
->_address
= NULL
;
291 memory
->_peerAddress
= NULL
;
292 memory
->_context
.info
= NULL
;
293 memory
->_context
.retain
= NULL
;
294 memory
->_context
.release
= NULL
;
295 memory
->_context
.copyDescription
= NULL
;
296 memory
->_callout
= callout
;
297 if (NULL
!= context
) {
298 objc_memmove_collectable(&memory
->_context
, context
, sizeof(CFSocketContext
));
299 memory
->_context
.info
= context
->retain
? (void *)context
->retain(context
->info
) : context
->info
;
302 struct __shared_blob
*shared
= malloc(sizeof(struct __shared_blob
));
303 shared
->_rdsrc
= NULL
;
304 shared
->_wrsrc
= NULL
;
305 shared
->_source
= NULL
;
306 shared
->_socket
= ufd
;
307 shared
->_closeFD
= true; // copy of _closeOnInvalidate
308 shared
->_refCnt
= 1; // one for the CFSocket
309 memory
->_shared
= shared
;
311 if (memory
->_wantReadType
) {
312 dispatch_source_t dsrc
= NULL
;
314 dsrc
= dispatch_source_create(DISPATCH_SOURCE_TYPE_READ
, ufd
, 0, __sockQueue());
316 dsrc
= dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER
, 0, 0, __sockQueue());
317 dispatch_source_set_timer(dsrc
, dispatch_time(DISPATCH_TIME_NOW
, 0), NSEC_PER_SEC
/ 2, NSEC_PER_SEC
);
319 dispatch_block_t event_block
= ^{
320 memory
->_readable
= true;
321 if (!memory
->_rsuspended
) {
322 dispatch_suspend(dsrc
);
323 memory
->_rsuspended
= true;
325 if (shared
->_source
) {
326 CFRunLoopSourceSignal(shared
->_source
);
327 _CFRunLoopSourceWakeUpRunLoops(shared
->_source
);
330 dispatch_block_t cancel_block
= ^{
331 shared
->_rdsrc
= NULL
;
333 if (0 == shared
->_refCnt
) {
334 if (shared
->_closeFD
) close(shared
->_socket
);
337 dispatch_release(dsrc
);
339 dispatch_source_set_event_handler(dsrc
, event_block
);
340 dispatch_source_set_cancel_handler(dsrc
, cancel_block
);
341 shared
->_rdsrc
= dsrc
;
343 if (memory
->_wantWrite
|| memory
->_wantConnect
) {
344 dispatch_source_t dsrc
= NULL
;
346 dsrc
= dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE
, ufd
, 0, __sockQueue());
348 dsrc
= dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER
, 0, 0, __sockQueue());
349 dispatch_source_set_timer(dsrc
, dispatch_time(DISPATCH_TIME_NOW
, 0), NSEC_PER_SEC
/ 2, NSEC_PER_SEC
);
351 dispatch_block_t event_block
= ^{
352 memory
->_writeable
= true;
353 if (!memory
->_wsuspended
) {
354 dispatch_suspend(dsrc
);
355 memory
->_wsuspended
= true;
357 if (shared
->_source
) {
358 CFRunLoopSourceSignal(shared
->_source
);
359 _CFRunLoopSourceWakeUpRunLoops(shared
->_source
);
362 dispatch_block_t cancel_block
= ^{
363 shared
->_wrsrc
= NULL
;
365 if (0 == shared
->_refCnt
) {
366 if (shared
->_closeFD
) close(shared
->_socket
);
369 dispatch_release(dsrc
);
371 dispatch_source_set_event_handler(dsrc
, event_block
);
372 dispatch_source_set_cancel_handler(dsrc
, cancel_block
);
373 shared
->_wrsrc
= dsrc
;
376 if (shared
->_rdsrc
) {
379 if (shared
->_wrsrc
) {
383 memory
->_state
= kCFSocketStateReady
;
384 CFArrayAppendValue(__CFAllSockets
, memory
);
387 // CFLog(5, CFSTR("CFSocketCreateWithNative(): created socket %p with callbacks 0x%x"), sock, callBackTypes);
391 CFSocketNativeHandle
CFSocketGetNative(CFSocketRef sock
) {
392 CHECK_FOR_FORK_RET(INVALID_SOCKET
);
393 __CFGenericValidateType(sock
, CFSocketGetTypeID());
394 return sock
->_shared
? sock
->_shared
->_socket
: INVALID_SOCKET
;
397 void CFSocketGetContext(CFSocketRef sock
, CFSocketContext
*context
) {
398 __CFGenericValidateType(sock
, CFSocketGetTypeID());
399 CFAssert1(0 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__
);
400 objc_memmove_collectable(context
, &sock
->_context
, sizeof(CFSocketContext
));
403 CFDataRef
CFSocketCopyAddress(CFSocketRef sock
) {
404 CHECK_FOR_FORK_RET(NULL
);
405 __CFGenericValidateType(sock
, CFSocketGetTypeID());
406 __block CFDataRef result
= NULL
;
407 dispatch_sync(__sockQueue(), ^{
408 if (!sock
->_address
) {
409 if (!__CFSocketIsValid(sock
)) return;
410 uint8_t name
[MAX_SOCKADDR_LEN
];
411 int namelen
= sizeof(name
);
412 int ret
= getsockname(sock
->_shared
->_socket
, (struct sockaddr
*)name
, (socklen_t
*)&namelen
);
413 if (0 == ret
&& 0 < namelen
) {
414 sock
->_address
= CFDataCreate(CFGetAllocator(sock
), name
, namelen
);
417 result
= sock
->_address
? (CFDataRef
)CFRetain(sock
->_address
) : NULL
;
419 // CFLog(5, CFSTR("CFSocketCopyAddress(): created socket %p address %@"), sock, result);
423 CFDataRef
CFSocketCopyPeerAddress(CFSocketRef sock
) {
424 CHECK_FOR_FORK_RET(NULL
);
425 __CFGenericValidateType(sock
, CFSocketGetTypeID());
426 __block CFDataRef result
= NULL
;
427 dispatch_sync(__sockQueue(), ^{
428 if (!sock
->_peerAddress
) {
429 if (!__CFSocketIsValid(sock
)) return;
430 uint8_t name
[MAX_SOCKADDR_LEN
];
431 int namelen
= sizeof(name
);
432 int ret
= getpeername(sock
->_shared
->_socket
, (struct sockaddr
*)name
, (socklen_t
*)&namelen
);
433 if (0 == ret
&& 0 < namelen
) {
434 sock
->_peerAddress
= CFDataCreate(CFGetAllocator(sock
), name
, namelen
);
437 result
= sock
->_peerAddress
? (CFDataRef
)CFRetain(sock
->_peerAddress
) : NULL
;
439 // CFLog(5, CFSTR("CFSocketCopyPeerAddress(): created socket %p peer address %@"), sock, result);
443 CFOptionFlags
CFSocketGetSocketFlags(CFSocketRef sock
) {
445 __CFGenericValidateType(sock
, CFSocketGetTypeID());
446 __block CFOptionFlags flags
= 0;
447 dispatch_sync(__sockQueue(), ^{
448 if (sock
->_reenableRead
) flags
|= sock
->_wantReadType
; // flags are same as types here
449 if (sock
->_reeanbleWrite
) flags
|= kCFSocketAutomaticallyReenableWriteCallBack
;
450 if (sock
->_leaveErrors
) flags
|= kCFSocketLeaveErrors
;
451 if (sock
->_closeOnInvalidate
) flags
|= kCFSocketCloseOnInvalidate
;
453 // CFLog(5, CFSTR("CFSocketGetSocketFlags(%p): -> 0x%x"), sock, flags);
457 void CFSocketSetSocketFlags(CFSocketRef sock
, CFOptionFlags flags
) {
459 // CFLog(5, CFSTR("CFSocketSetSocketFlags(%p, 0x%x) starting"), sock, flags);
460 __CFGenericValidateType(sock
, CFSocketGetTypeID());
461 dispatch_sync(__sockQueue(), ^{
462 sock
->_reenableRead
= (sock
->_wantReadType
&& ((flags
& 0x3) == sock
->_wantReadType
)) ? true : false;
463 sock
->_reeanbleWrite
= (sock
->_wantWrite
&& (flags
& kCFSocketAutomaticallyReenableWriteCallBack
)) ? true : false;
464 sock
->_leaveErrors
= (flags
& kCFSocketLeaveErrors
) ? true : false;
465 sock
->_closeOnInvalidate
= (flags
& kCFSocketCloseOnInvalidate
) ? true : false;
466 if (sock
->_shared
) sock
->_shared
->_closeFD
= sock
->_closeOnInvalidate
;
468 // CFLog(5, CFSTR("CFSocketSetSocketFlags(%p, 0x%x) done"), sock, flags);
471 void CFSocketEnableCallBacks(CFSocketRef sock
, CFOptionFlags callBackTypes
) {
472 CHECK_FOR_FORK_RET();
473 __CFGenericValidateType(sock
, CFSocketGetTypeID());
474 // CFLog(5, CFSTR("CFSocketEnableCallBacks(%p, 0x%x) starting"), sock, callBackTypes);
475 dispatch_sync(__sockQueue(), ^{
476 if (!__CFSocketIsValid(sock
)) return;
477 if (sock
->_wantReadType
&& (callBackTypes
& 0x3) == sock
->_wantReadType
) {
478 if (sock
->_rsuspended
&& sock
->_shared
->_rdsrc
) {
479 sock
->_rsuspended
= false;
480 dispatch_resume(sock
->_shared
->_rdsrc
);
482 sock
->_readDisabled
= false;
484 if (sock
->_wantWrite
&& (callBackTypes
& kCFSocketWriteCallBack
)) {
485 if (sock
->_wsuspended
&& sock
->_shared
->_wrsrc
) {
486 sock
->_wsuspended
= false;
487 dispatch_resume(sock
->_shared
->_wrsrc
);
489 sock
->_writeDisabled
= false;
491 if (sock
->_wantConnect
&& !sock
->_connected
&& (callBackTypes
& kCFSocketConnectCallBack
)) {
492 if (sock
->_wsuspended
&& sock
->_shared
->_wrsrc
) {
493 sock
->_wsuspended
= false;
494 dispatch_resume(sock
->_shared
->_wrsrc
);
496 sock
->_connectDisabled
= false;
499 // CFLog(5, CFSTR("CFSocketEnableCallBacks(%p, 0x%x) done"), sock, callBackTypes);
502 void CFSocketDisableCallBacks(CFSocketRef sock
, CFOptionFlags callBackTypes
) {
503 CHECK_FOR_FORK_RET();
504 __CFGenericValidateType(sock
, CFSocketGetTypeID());
505 // CFLog(5, CFSTR("CFSocketDisableCallBacks(%p, 0x%x) starting"), sock, callBackTypes);
506 dispatch_sync(__sockQueue(), ^{
507 if (!__CFSocketIsValid(sock
)) return;
508 if (sock
->_wantReadType
&& (callBackTypes
& 0x3) == sock
->_wantReadType
) {
509 if (!sock
->_rsuspended
&& sock
->_shared
->_rdsrc
) {
510 dispatch_suspend(sock
->_shared
->_rdsrc
);
511 sock
->_rsuspended
= true;
513 sock
->_readDisabled
= true;
515 if (sock
->_wantWrite
&& (callBackTypes
& kCFSocketWriteCallBack
)) {
516 if (!sock
->_wsuspended
&& sock
->_shared
->_wrsrc
) {
517 dispatch_suspend(sock
->_shared
->_wrsrc
);
518 sock
->_wsuspended
= true;
520 sock
->_writeDisabled
= true;
522 if (sock
->_wantConnect
&& !sock
->_connected
&& (callBackTypes
& kCFSocketConnectCallBack
)) {
523 if (!sock
->_wsuspended
&& sock
->_shared
->_wrsrc
) {
524 dispatch_suspend(sock
->_shared
->_wrsrc
);
525 sock
->_wsuspended
= true;
527 sock
->_connectDisabled
= true;
530 // CFLog(5, CFSTR("CFSocketDisableCallBacks(%p, 0x%x) done"), sock, callBackTypes);
533 void CFSocketInvalidate(CFSocketRef sock
) {
534 CHECK_FOR_FORK_RET();
535 __CFGenericValidateType(sock
, CFSocketGetTypeID());
537 // CFLog(5, CFSTR("CFSocketInvalidate(%p) starting"), sock);
538 __block CFRunLoopSourceRef source
= NULL
;
539 __block Boolean wasReady
= false;
540 dispatch_sync(__sockQueue(), ^{
541 wasReady
= (sock
->_state
== kCFSocketStateReady
);
543 sock
->_state
= kCFSocketStateInvalidating
;
545 for (CFIndex idx
= 0, cnt
= CFArrayGetCount(__CFAllSockets
); idx
< cnt
; idx
++) {
546 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFAllSockets
, idx
);
548 CFArrayRemoveValueAtIndex(__CFAllSockets
, idx
);
552 if (sock
->_shared
->_rdsrc
) {
553 dispatch_source_cancel(sock
->_shared
->_rdsrc
);
554 if (sock
->_rsuspended
) {
555 sock
->_rsuspended
= false;
556 dispatch_resume(sock
->_shared
->_rdsrc
);
559 if (sock
->_shared
->_wrsrc
) {
560 dispatch_source_cancel(sock
->_shared
->_wrsrc
);
561 if (sock
->_wsuspended
) {
562 sock
->_wsuspended
= false;
563 dispatch_resume(sock
->_shared
->_wrsrc
);
566 source
= sock
->_shared
->_source
;
567 sock
->_shared
->_source
= NULL
;
568 sock
->_shared
->_refCnt
--;
569 if (0 == sock
->_shared
->_refCnt
) {
570 if (sock
->_shared
->_closeFD
) close(sock
->_shared
->_socket
);
573 sock
->_shared
= NULL
;
577 if (NULL
!= source
) {
578 CFRunLoopSourceInvalidate(source
);
581 void *info
= sock
->_context
.info
;
582 sock
->_context
.info
= NULL
;
583 if (sock
->_context
.release
) {
584 sock
->_context
.release(info
);
586 sock
->_state
= kCFSocketStateInvalid
;
589 // CFLog(5, CFSTR("CFSocketInvalidate(%p) done%s"), sock, wasReady ? " -- done on this thread" : "");
593 Boolean
CFSocketIsValid(CFSocketRef sock
) {
594 __CFGenericValidateType(sock
, CFSocketGetTypeID());
595 return __CFSocketIsValid(sock
);
599 static void __CFSocketPerform(void *info
) { // CFRunLoop should only call this on one thread at a time
600 CHECK_FOR_FORK_RET();
601 CFSocketRef sock
= (CFSocketRef
)info
;
603 // CFLog(5, CFSTR("__CFSocketPerform(%p) starting '%@'"), sock, sock);
604 __block Boolean doRead
= false, doWrite
= false, doConnect
= false, isValid
= false;
605 __block
int fd
= INVALID_SOCKET
;
606 __block SInt32 errorCode
= 0;
607 dispatch_sync(__sockQueue(), ^{
608 isValid
= __CFSocketIsValid(sock
);
609 if (!isValid
) return;
610 doRead
= sock
->_readable
&& sock
->_wantReadType
&& !sock
->_readDisabled
;
611 doWrite
= sock
->_writeable
&& sock
->_wantWrite
&& !sock
->_writeDisabled
;
612 doConnect
= sock
->_writeable
&& sock
->_wantConnect
&& !sock
->_connectDisabled
&& !sock
->_connected
;
613 if (doRead
) sock
->_readable
= false;
614 if (doWrite
|| doConnect
) sock
->_writeable
= false;
616 fd
= sock
->_shared
->_socket
;
618 if (isValid
&& !sock
->_leaveErrors
&& (doWrite
|| doConnect
)) { // not on read, for whatever reason
619 int errorSize
= sizeof(errorCode
);
620 int ret
= getsockopt(fd
, SOL_SOCKET
, SO_ERROR
, (void *)&errorCode
, (socklen_t
*)&errorSize
);
621 if (0 != ret
) errorCode
= 0;
622 sock
->_error
= errorCode
;
624 sock
->_connected
= true;
626 // CFLog(5, CFSTR("__CFSocketPerform(%p) isValid:%d, doRead:%d, doWrite:%d, doConnect:%d error:%d"), sock, isValid, doRead, doWrite, doConnect, errorCode);
627 if (!isValid
) return;
629 void *context_info
= NULL
;
630 void (*context_release
)(const void *) = NULL
;
631 if (sock
->_context
.retain
) {
632 context_info
= (void *)sock
->_context
.retain(sock
->_context
.info
);
633 context_release
= sock
->_context
.release
;
635 context_info
= sock
->_context
.info
;
638 Boolean calledOut
= false;
640 // CFLog(5, CFSTR("__CFSocketPerform(%p) doing connect callback"), sock);
641 if (sock
->_callout
) sock
->_callout(sock
, kCFSocketConnectCallBack
, NULL
, (0 != errorCode
) ? &errorCode
: NULL
, context_info
);
642 // CFLog(5, CFSTR("__CFSocketPerform(%p) doing connect callback done"), sock);
645 if (doRead
&& (!calledOut
|| __CFSocketIsValid(sock
))) {
646 switch (sock
->_wantReadType
) {
647 case kCFSocketReadCallBack
:
648 // CFLog(5, CFSTR("__CFSocketPerform(%p) doing read callback"), sock);
649 if (sock
->_callout
) sock
->_callout(sock
, kCFSocketReadCallBack
, NULL
, NULL
, context_info
);
650 // CFLog(5, CFSTR("__CFSocketPerform(%p) doing read callback done"), sock);
653 case kCFSocketAcceptCallBack
: {
654 uint8_t name
[MAX_SOCKADDR_LEN
];
655 int namelen
= sizeof(name
);
656 int new_fd
= accept(fd
, (struct sockaddr
*)name
, (socklen_t
*)&namelen
);
657 if (INVALID_SOCKET
!= new_fd
) {
658 CFDataRef address
= CFDataCreate(CFGetAllocator(sock
), name
, namelen
);
659 if (sock
->_callout
) sock
->_callout(sock
, kCFSocketAcceptCallBack
, address
, &new_fd
, context_info
);
665 case kCFSocketDataCallBack
: {
666 uint8_t name
[MAX_SOCKADDR_LEN
];
667 int namelen
= sizeof(name
);
669 int ret
= ioctl(fd
, FIONREAD
, &avail
);
670 if (ret
< 0 || avail
< 256) avail
= 256;
671 if ((1 << 20) < avail
) avail
= (1 << 20);
672 CFMutableDataRef data
= CFDataCreateMutable(CFGetAllocator(sock
), 0);
673 CFDataSetLength(data
, avail
);
674 ssize_t len
= recvfrom(fd
, CFDataGetMutableBytePtr(data
), avail
, 0, (struct sockaddr
*)name
, (socklen_t
*)&namelen
);
675 CFIndex datalen
= (len
< 0) ? 0 : len
;
676 CFDataSetLength(data
, datalen
);
677 CFDataRef address
= NULL
;
679 address
= CFDataCreate(CFGetAllocator(sock
), name
, namelen
);
680 } else if (sock
->_connOriented
) {
681 address
= CFSocketCopyPeerAddress(sock
);
683 if (NULL
== address
) {
684 address
= CFDataCreate(CFGetAllocator(sock
), NULL
, 0);
686 if (sock
->_callout
) sock
->_callout(sock
, kCFSocketDataCallBack
, address
, data
, context_info
);
688 if (0 == datalen
) CFSocketInvalidate(sock
);
689 if (address
) CFRelease(address
);
695 if (doWrite
&& (!calledOut
|| __CFSocketIsValid(sock
))) {
696 if (0 == errorCode
) {
697 // CFLog(5, CFSTR("__CFSocketPerform(%p) doing write callback"), sock);
698 if (sock
->_callout
) sock
->_callout(sock
, kCFSocketWriteCallBack
, NULL
, NULL
, context_info
);
699 // CFLog(5, CFSTR("__CFSocketPerform(%p) doing write callback done"), sock);
703 // CFLog(5, CFSTR("__CFSocketPerform(%p) callouts done"), sock);
705 dispatch_sync(__sockQueue(), ^{
706 if (!__CFSocketIsValid(sock
)) return;
707 if (doRead
&& sock
->_reenableRead
) {
708 // CFLog(5, CFSTR("__CFSocketPerform(%p) reenabling read"), sock);
709 if (sock
->_rsuspended
&& sock
->_shared
->_rdsrc
) {
710 sock
->_rsuspended
= false;
711 dispatch_resume(sock
->_shared
->_rdsrc
);
714 if (doWrite
&& sock
->_reeanbleWrite
) {
715 // CFLog(5, CFSTR("__CFSocketPerform(%p) reenabling write"), sock);
716 if (sock
->_wsuspended
&& sock
->_shared
->_wrsrc
) {
717 sock
->_wsuspended
= false;
718 dispatch_resume(sock
->_shared
->_wrsrc
);
723 if (context_release
) {
724 context_release(context_info
);
726 CHECK_FOR_FORK_RET();
727 // CFLog(5, CFSTR("__CFSocketPerform(%p) done"), sock);
730 static void __CFSocketSchedule(void *info
, CFRunLoopRef rl
, CFStringRef mode
) {
731 CFSocketRef sock
= (CFSocketRef
)info
;
732 int32_t newVal
= OSAtomicIncrement32Barrier(&sock
->_runLoopCounter
);
733 if (1 == newVal
) { // on a transition from 0->1, the old code forced all desired callbacks enabled
734 CFOptionFlags types
= sock
->_wantReadType
| (sock
->_wantWrite
? kCFSocketWriteCallBack
: 0) | (sock
->_wantConnect
? kCFSocketConnectCallBack
: 0);
735 CFSocketEnableCallBacks(sock
, types
);
740 static void __CFSocketCancel(void *info
, CFRunLoopRef rl
, CFStringRef mode
) {
741 CFSocketRef sock
= (CFSocketRef
)info
;
742 OSAtomicDecrement32Barrier(&sock
->_runLoopCounter
);
746 CFRunLoopSourceRef
CFSocketCreateRunLoopSource(CFAllocatorRef allocator
, CFSocketRef sock
, CFIndex order
) {
747 CHECK_FOR_FORK_RET(NULL
);
748 __CFGenericValidateType(sock
, CFSocketGetTypeID());
749 __block CFRunLoopSourceRef result
= NULL
;
750 dispatch_sync(__sockQueue(), ^{
751 if (!__CFSocketIsValid(sock
)) return;
752 if (NULL
== sock
->_shared
->_source
) {
753 CFRunLoopSourceContext context
;
755 context
.info
= (void *)sock
;
756 context
.retain
= (const void *(*)(const void *))CFRetain
;
757 context
.release
= (void (*)(const void *))CFRelease
;
758 context
.copyDescription
= (CFStringRef (*)(const void *))__CFSocketCopyDescription
;
759 context
.equal
= NULL
;
761 context
.schedule
= __CFSocketSchedule
;
762 context
.cancel
= __CFSocketCancel
;
763 context
.perform
= __CFSocketPerform
;
764 sock
->_shared
->_source
= CFRunLoopSourceCreate(allocator
, order
, (CFRunLoopSourceContext
*)&context
);
765 if (sock
->_shared
->_source
) {
766 if (sock
->_wantReadType
) {
767 if (sock
->_rsuspended
&& sock
->_shared
->_rdsrc
) {
768 sock
->_rsuspended
= false;
769 dispatch_resume(sock
->_shared
->_rdsrc
);
772 if (sock
->_wantWrite
|| (sock
->_wantConnect
&& !sock
->_connected
)) {
773 if (sock
->_wsuspended
&& sock
->_shared
->_wrsrc
) {
774 sock
->_wsuspended
= false;
775 dispatch_resume(sock
->_shared
->_wrsrc
);
780 result
= sock
->_shared
->_source
? (CFRunLoopSourceRef
)CFRetain(sock
->_shared
->_source
) : NULL
;
782 // CFLog(5, CFSTR("CFSocketCreateRunLoopSource(%p) => %p"), sock, result);
787 void __CFSocketSetSocketReadBufferAttrs(CFSocketRef s
, CFTimeInterval timeout
, CFIndex length
) {
790 CFIndex
__CFSocketRead(CFSocketRef s
, UInt8
* buffer
, CFIndex length
, int* error
) {
792 int ret
= read(CFSocketGetNative(s
), buffer
, length
);
799 Boolean
__CFSocketGetBytesAvailable(CFSocketRef s
, CFIndex
* ctBytesAvailable
) {
801 int ret
= ioctl(CFSocketGetNative(s
), FIONREAD
, &bytesAvailable
);
802 if (ret
< 0) return false;
803 *ctBytesAvailable
= (CFIndex
)bytesAvailable
;
808 #else /* not NEW_SOCKET */
811 #include <CoreFoundation/CFSocket.h>
812 #include <sys/types.h>
815 #include <sys/resource.h>
816 #include <sys/sysctl.h>
817 #include <CoreFoundation/CFArray.h>
818 #include <CoreFoundation/CFData.h>
819 #include <CoreFoundation/CFDictionary.h>
820 #include <CoreFoundation/CFRunLoop.h>
821 #include <CoreFoundation/CFString.h>
822 #include <CoreFoundation/CFPropertyList.h>
823 #include "CFInternal.h"
827 // On Mach we use a v0 RunLoopSource to make client callbacks. That source is signalled by a
828 // separate SocketManager thread who uses select() to watch the sockets' fds.
830 //#define LOG_CFSOCKET
832 #define INVALID_SOCKET (CFSocketNativeHandle)(-1)
834 #define closesocket(a) close((a))
835 #define ioctlsocket(a,b,c) ioctl((a),(b),(c))
837 CF_INLINE
int __CFSocketLastError(void) {
838 return thread_errno();
841 CF_INLINE CFIndex
__CFSocketFdGetSize(CFDataRef fdSet
) {
842 return NBBY
* CFDataGetLength(fdSet
);
845 CF_INLINE Boolean
__CFSocketFdSet(CFSocketNativeHandle sock
, CFMutableDataRef fdSet
) {
846 /* returns true if a change occurred, false otherwise */
847 Boolean retval
= false;
848 if (INVALID_SOCKET
!= sock
&& 0 <= sock
) {
849 CFIndex numFds
= NBBY
* CFDataGetLength(fdSet
);
851 if (sock
>= numFds
) {
852 CFIndex oldSize
= numFds
/ NFDBITS
, newSize
= (sock
+ NFDBITS
) / NFDBITS
, changeInBytes
= (newSize
- oldSize
) * sizeof(fd_mask
);
853 CFDataIncreaseLength(fdSet
, changeInBytes
);
854 fds_bits
= (fd_mask
*)CFDataGetMutableBytePtr(fdSet
);
855 memset(fds_bits
+ oldSize
, 0, changeInBytes
);
857 fds_bits
= (fd_mask
*)CFDataGetMutableBytePtr(fdSet
);
859 if (!FD_ISSET(sock
, (fd_set
*)fds_bits
)) {
861 FD_SET(sock
, (fd_set
*)fds_bits
);
868 #define MAX_SOCKADDR_LEN 256
869 #define MAX_DATA_SIZE 65535
870 #define MAX_CONNECTION_ORIENTED_DATA_SIZE 32768
872 /* locks are to be acquired in the following order:
873 (1) __CFAllSocketsLock
874 (2) an individual CFSocket's lock
875 (3) __CFActiveSocketsLock
877 static CFSpinLock_t __CFAllSocketsLock
= CFSpinLockInit
; /* controls __CFAllSockets */
878 static CFMutableDictionaryRef __CFAllSockets
= NULL
;
879 static CFSpinLock_t __CFActiveSocketsLock
= CFSpinLockInit
; /* controls __CFRead/WriteSockets, __CFRead/WriteSocketsFds, __CFSocketManagerThread, and __CFSocketManagerIteration */
880 static volatile UInt32 __CFSocketManagerIteration
= 0;
881 static CFMutableArrayRef __CFWriteSockets
= NULL
;
882 static CFMutableArrayRef __CFReadSockets
= NULL
;
883 static CFMutableDataRef __CFWriteSocketsFds
= NULL
;
884 static CFMutableDataRef __CFReadSocketsFds
= NULL
;
885 static CFDataRef zeroLengthData
= NULL
;
886 static Boolean __CFReadSocketsTimeoutInvalid
= true; /* rebuild the timeout value before calling select */
888 static CFSocketNativeHandle __CFWakeupSocketPair
[2] = {INVALID_SOCKET
, INVALID_SOCKET
};
889 static void *__CFSocketManagerThread
= NULL
;
891 static void __CFSocketDoCallback(CFSocketRef s
, CFDataRef data
, CFDataRef address
, CFSocketNativeHandle sock
);
896 unsigned client
:8; // flags set by client (reenable, CloseOnInvalidate)
897 unsigned disabled
:8; // flags marking disabled callbacks
898 unsigned connected
:1; // Are we connected yet? (also true for connectionless sockets)
899 unsigned writableHint
:1; // Did the polling the socket show it to be writable?
900 unsigned closeSignaled
:1; // Have we seen FD_CLOSE? (only used on Win32)
904 CFSpinLock_t _writeLock
;
905 CFSocketNativeHandle _socket
; /* immutable */
909 CFDataRef _peerAddress
;
910 SInt32 _socketSetCount
;
911 CFRunLoopSourceRef _source0
; // v0 RLS, messaged from SocketMgr
912 CFMutableArrayRef _runLoops
;
913 CFSocketCallBack _callout
; /* immutable */
914 CFSocketContext _context
; /* immutable */
915 CFMutableArrayRef _dataQueue
; // queues to pass data from SocketMgr thread
916 CFMutableArrayRef _addressQueue
;
918 struct timeval _readBufferTimeout
;
919 CFMutableDataRef _readBuffer
;
920 CFIndex _bytesToBuffer
; /* is length of _readBuffer */
921 CFIndex _bytesToBufferPos
; /* where the next _CFSocketRead starts from */
922 CFIndex _bytesToBufferReadPos
; /* Where the buffer will next be read into (always after _bytesToBufferPos, but less than _bytesToBuffer) */
924 int _bufferedReadError
;
926 CFMutableDataRef _leftoverBytes
;
929 /* Bit 6 in the base reserved bits is used for write-signalled state (mutable) */
930 /* Bit 5 in the base reserved bits is used for read-signalled state (mutable) */
931 /* Bit 4 in the base reserved bits is used for invalid state (mutable) */
932 /* Bits 0-3 in the base reserved bits are used for callback types (immutable) */
933 /* Of this, bits 0-1 are used for the read callback type. */
935 CF_INLINE Boolean
__CFSocketIsWriteSignalled(CFSocketRef s
) {
936 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 6, 6);
939 CF_INLINE
void __CFSocketSetWriteSignalled(CFSocketRef s
) {
940 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 6, 6, 1);
943 CF_INLINE
void __CFSocketUnsetWriteSignalled(CFSocketRef s
) {
944 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 6, 6, 0);
947 CF_INLINE Boolean
__CFSocketIsReadSignalled(CFSocketRef s
) {
948 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 5, 5);
951 CF_INLINE
void __CFSocketSetReadSignalled(CFSocketRef s
) {
952 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 5, 5, 1);
955 CF_INLINE
void __CFSocketUnsetReadSignalled(CFSocketRef s
) {
956 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 5, 5, 0);
959 CF_INLINE Boolean
__CFSocketIsValid(CFSocketRef s
) {
960 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 4, 4);
963 CF_INLINE
void __CFSocketSetValid(CFSocketRef s
) {
964 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 4, 4, 1);
967 CF_INLINE
void __CFSocketUnsetValid(CFSocketRef s
) {
968 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 4, 4, 0);
971 CF_INLINE
uint8_t __CFSocketCallBackTypes(CFSocketRef s
) {
972 return (uint8_t)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 3, 0);
975 CF_INLINE
uint8_t __CFSocketReadCallBackType(CFSocketRef s
) {
976 return (uint8_t)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 1, 0);
979 CF_INLINE
void __CFSocketSetCallBackTypes(CFSocketRef s
, uint8_t types
) {
980 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 3, 0, types
& 0xF);
983 CF_INLINE
void __CFSocketLock(CFSocketRef s
) {
984 __CFSpinLock(&(s
->_lock
));
987 CF_INLINE
void __CFSocketUnlock(CFSocketRef s
) {
988 __CFSpinUnlock(&(s
->_lock
));
991 CF_INLINE Boolean
__CFSocketIsConnectionOriented(CFSocketRef s
) {
992 return (SOCK_STREAM
== s
->_socketType
|| SOCK_SEQPACKET
== s
->_socketType
);
995 CF_INLINE Boolean
__CFSocketIsScheduled(CFSocketRef s
) {
996 return (s
->_socketSetCount
> 0);
999 CF_INLINE
void __CFSocketEstablishAddress(CFSocketRef s
) {
1000 /* socket should already be locked */
1001 uint8_t name
[MAX_SOCKADDR_LEN
];
1002 int namelen
= sizeof(name
);
1003 if (__CFSocketIsValid(s
) && NULL
== s
->_address
&& INVALID_SOCKET
!= s
->_socket
&& 0 == getsockname(s
->_socket
, (struct sockaddr
*)name
, (socklen_t
*)&namelen
) && NULL
!= name
&& 0 < namelen
) {
1004 s
->_address
= CFDataCreate(CFGetAllocator(s
), name
, namelen
);
1008 CF_INLINE
void __CFSocketEstablishPeerAddress(CFSocketRef s
) {
1009 /* socket should already be locked */
1010 uint8_t name
[MAX_SOCKADDR_LEN
];
1011 int namelen
= sizeof(name
);
1012 if (__CFSocketIsValid(s
) && NULL
== s
->_peerAddress
&& INVALID_SOCKET
!= s
->_socket
&& 0 == getpeername(s
->_socket
, (struct sockaddr
*)name
, (socklen_t
*)&namelen
) && NULL
!= name
&& 0 < namelen
) {
1013 s
->_peerAddress
= CFDataCreate(CFGetAllocator(s
), name
, namelen
);
1017 static Boolean
__CFNativeSocketIsValid(CFSocketNativeHandle sock
) {
1018 SInt32 flags
= fcntl(sock
, F_GETFL
, 0);
1019 return !(0 > flags
&& EBADF
== thread_errno());
1022 CF_INLINE Boolean
__CFSocketFdClr(CFSocketNativeHandle sock
, CFMutableDataRef fdSet
) {
1023 /* returns true if a change occurred, false otherwise */
1024 Boolean retval
= false;
1025 if (INVALID_SOCKET
!= sock
&& 0 <= sock
) {
1026 CFIndex numFds
= NBBY
* CFDataGetLength(fdSet
);
1028 if (sock
< numFds
) {
1029 fds_bits
= (fd_mask
*)CFDataGetMutableBytePtr(fdSet
);
1030 if (FD_ISSET(sock
, (fd_set
*)fds_bits
)) {
1032 FD_CLR(sock
, (fd_set
*)fds_bits
);
1039 static SInt32
__CFSocketCreateWakeupSocketPair(void) {
1040 return socketpair(PF_LOCAL
, SOCK_DGRAM
, 0, __CFWakeupSocketPair
);
1044 // Version 0 RunLoopSources set a mask in an FD set to control what socket activity we hear about.
1045 CF_INLINE Boolean
__CFSocketSetFDForRead(CFSocketRef s
) {
1046 __CFReadSocketsTimeoutInvalid
= true;
1047 return __CFSocketFdSet(s
->_socket
, __CFReadSocketsFds
);
1050 CF_INLINE Boolean
__CFSocketClearFDForRead(CFSocketRef s
) {
1051 __CFReadSocketsTimeoutInvalid
= true;
1052 return __CFSocketFdClr(s
->_socket
, __CFReadSocketsFds
);
1055 CF_INLINE Boolean
__CFSocketSetFDForWrite(CFSocketRef s
) {
1056 // CFLog(5, CFSTR("__CFSocketSetFDForWrite(%p)"), s);
1057 return __CFSocketFdSet(s
->_socket
, __CFWriteSocketsFds
);
1060 CF_INLINE Boolean
__CFSocketClearFDForWrite(CFSocketRef s
) {
1061 // CFLog(5, CFSTR("__CFSocketClearFDForWrite(%p)"), s);
1062 return __CFSocketFdClr(s
->_socket
, __CFWriteSocketsFds
);
1066 // CFNetwork needs to call this, especially for Win32 to get WSAStartup
1067 static void __CFSocketInitializeSockets(void) {
1068 __CFWriteSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
);
1069 __CFReadSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
);
1070 __CFWriteSocketsFds
= CFDataCreateMutable(kCFAllocatorSystemDefault
, 0);
1071 __CFReadSocketsFds
= CFDataCreateMutable(kCFAllocatorSystemDefault
, 0);
1072 zeroLengthData
= CFDataCreateMutable(kCFAllocatorSystemDefault
, 0);
1073 if (0 > __CFSocketCreateWakeupSocketPair()) {
1074 CFLog(kCFLogLevelWarning
, CFSTR("*** Could not create wakeup socket pair for CFSocket!!!"));
1077 /* wakeup sockets must be non-blocking */
1078 ioctlsocket(__CFWakeupSocketPair
[0], FIONBIO
, &yes
);
1079 ioctlsocket(__CFWakeupSocketPair
[1], FIONBIO
, &yes
);
1080 __CFSocketFdSet(__CFWakeupSocketPair
[1], __CFReadSocketsFds
);
1084 static CFRunLoopRef
__CFSocketCopyRunLoopToWakeUp(CFSocketRef s
) {
1085 CFRunLoopRef rl
= NULL
;
1086 SInt32 idx
, cnt
= CFArrayGetCount(s
->_runLoops
);
1088 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(s
->_runLoops
, 0);
1089 for (idx
= 1; NULL
!= rl
&& idx
< cnt
; idx
++) {
1090 CFRunLoopRef value
= (CFRunLoopRef
)CFArrayGetValueAtIndex(s
->_runLoops
, idx
);
1091 if (value
!= rl
) rl
= NULL
;
1093 if (NULL
== rl
) { /* more than one different rl, so we must pick one */
1094 /* ideally, this would be a run loop which isn't also in a
1095 * signaled state for this or another source, but that's tricky;
1096 * we pick one that is running in an appropriate mode for this
1097 * source, and from those if possible one that is waiting; then
1098 * we move this run loop to the end of the list to scramble them
1099 * a bit, and always search from the front */
1100 Boolean foundIt
= false, foundBackup
= false;
1101 SInt32 foundIdx
= 0;
1102 for (idx
= 0; !foundIt
&& idx
< cnt
; idx
++) {
1103 CFRunLoopRef value
= (CFRunLoopRef
)CFArrayGetValueAtIndex(s
->_runLoops
, idx
);
1104 CFStringRef currentMode
= CFRunLoopCopyCurrentMode(value
);
1105 if (NULL
!= currentMode
) {
1106 if (CFRunLoopContainsSource(value
, s
->_source0
, currentMode
)) {
1107 if (CFRunLoopIsWaiting(value
)) {
1110 } else if (!foundBackup
) {
1115 CFRelease(currentMode
);
1118 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(s
->_runLoops
, foundIdx
);
1120 CFArrayRemoveValueAtIndex(s
->_runLoops
, foundIdx
);
1121 CFArrayAppendValue(s
->_runLoops
, rl
);
1129 // If callBackNow, we immediately do client callbacks, else we have to signal a v0 RunLoopSource so the
1130 // callbacks can happen in another thread.
1131 static void __CFSocketHandleWrite(CFSocketRef s
, Boolean callBackNow
) {
1132 SInt32 errorCode
= 0;
1133 int errorSize
= sizeof(errorCode
);
1134 CFOptionFlags writeCallBacksAvailable
;
1136 if (!CFSocketIsValid(s
)) return;
1137 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
1138 #if defined(LOG_CFSOCKET)
1139 if (errorCode
) fprintf(stdout
, "error %ld on socket %d\n", errorCode
, s
->_socket
);
1142 writeCallBacksAvailable
= __CFSocketCallBackTypes(s
) & (kCFSocketWriteCallBack
| kCFSocketConnectCallBack
);
1143 if ((s
->_f
.client
& kCFSocketConnectCallBack
) != 0) writeCallBacksAvailable
&= ~kCFSocketConnectCallBack
;
1144 if (!__CFSocketIsValid(s
) || ((s
->_f
.disabled
& writeCallBacksAvailable
) == writeCallBacksAvailable
)) {
1145 __CFSocketUnlock(s
);
1148 s
->_errorCode
= errorCode
;
1149 __CFSocketSetWriteSignalled(s
);
1150 // CFLog(5, CFSTR("__CFSocketHandleWrite() signalling write on socket %p"), s);
1151 #if defined(LOG_CFSOCKET)
1152 fprintf(stdout
, "write signaling source for socket %d\n", s
->_socket
);
1155 __CFSocketDoCallback(s
, NULL
, NULL
, 0);
1158 CFRunLoopSourceSignal(s
->_source0
);
1159 rl
= __CFSocketCopyRunLoopToWakeUp(s
);
1160 __CFSocketUnlock(s
);
1162 CFRunLoopWakeUp(rl
);
1168 static void __CFSocketHandleRead(CFSocketRef s
, Boolean causedByTimeout
)
1170 CFDataRef data
= NULL
, address
= NULL
;
1171 CFSocketNativeHandle sock
= INVALID_SOCKET
;
1172 if (!CFSocketIsValid(s
)) return;
1173 if (__CFSocketReadCallBackType(s
) == kCFSocketDataCallBack
) {
1174 uint8_t bufferArray
[MAX_CONNECTION_ORIENTED_DATA_SIZE
], *buffer
;
1175 uint8_t name
[MAX_SOCKADDR_LEN
];
1176 int namelen
= sizeof(name
);
1178 if (__CFSocketIsConnectionOriented(s
)) {
1179 buffer
= bufferArray
;
1180 recvlen
= recvfrom(s
->_socket
, buffer
, MAX_CONNECTION_ORIENTED_DATA_SIZE
, 0, (struct sockaddr
*)name
, (socklen_t
*)&namelen
);
1182 buffer
= malloc(MAX_DATA_SIZE
);
1183 if (buffer
) recvlen
= recvfrom(s
->_socket
, buffer
, MAX_DATA_SIZE
, 0, (struct sockaddr
*)name
, (socklen_t
*)&namelen
);
1185 #if defined(LOG_CFSOCKET)
1186 fprintf(stdout
, "read %ld bytes on socket %d\n", recvlen
, s
->_socket
);
1189 //??? should return error if <0
1190 /* zero-length data is the signal for perform to invalidate */
1191 data
= CFRetain(zeroLengthData
);
1193 data
= CFDataCreate(CFGetAllocator(s
), buffer
, recvlen
);
1195 if (buffer
&& buffer
!= bufferArray
) free(buffer
);
1197 if (!__CFSocketIsValid(s
)) {
1199 __CFSocketUnlock(s
);
1202 __CFSocketSetReadSignalled(s
);
1203 if (NULL
!= name
&& 0 < namelen
) {
1204 //??? possible optimizations: uniquing; storing last value
1205 address
= CFDataCreate(CFGetAllocator(s
), name
, namelen
);
1206 } else if (__CFSocketIsConnectionOriented(s
)) {
1207 if (NULL
== s
->_peerAddress
) __CFSocketEstablishPeerAddress(s
);
1208 if (NULL
!= s
->_peerAddress
) address
= CFRetain(s
->_peerAddress
);
1210 if (NULL
== address
) {
1211 address
= CFRetain(zeroLengthData
);
1213 if (NULL
== s
->_dataQueue
) {
1214 s
->_dataQueue
= CFArrayCreateMutable(CFGetAllocator(s
), 0, &kCFTypeArrayCallBacks
);
1216 if (NULL
== s
->_addressQueue
) {
1217 s
->_addressQueue
= CFArrayCreateMutable(CFGetAllocator(s
), 0, &kCFTypeArrayCallBacks
);
1219 CFArrayAppendValue(s
->_dataQueue
, data
);
1221 CFArrayAppendValue(s
->_addressQueue
, address
);
1224 && (s
->_f
.client
& kCFSocketDataCallBack
) != 0 && (s
->_f
.disabled
& kCFSocketDataCallBack
) == 0
1225 && __CFSocketIsScheduled(s
)
1227 __CFSpinLock(&__CFActiveSocketsLock
);
1228 /* restore socket to fds */
1229 __CFSocketSetFDForRead(s
);
1230 __CFSpinUnlock(&__CFActiveSocketsLock
);
1232 } else if (__CFSocketReadCallBackType(s
) == kCFSocketAcceptCallBack
) {
1233 uint8_t name
[MAX_SOCKADDR_LEN
];
1234 int namelen
= sizeof(name
);
1235 sock
= accept(s
->_socket
, (struct sockaddr
*)name
, (socklen_t
*)&namelen
);
1236 if (INVALID_SOCKET
== sock
) {
1237 //??? should return error
1240 if (NULL
!= name
&& 0 < namelen
) {
1241 address
= CFDataCreate(CFGetAllocator(s
), name
, namelen
);
1243 address
= CFRetain(zeroLengthData
);
1246 if (!__CFSocketIsValid(s
)) {
1249 __CFSocketUnlock(s
);
1252 __CFSocketSetReadSignalled(s
);
1253 if (NULL
== s
->_dataQueue
) {
1254 s
->_dataQueue
= CFArrayCreateMutable(CFGetAllocator(s
), 0, NULL
);
1256 if (NULL
== s
->_addressQueue
) {
1257 s
->_addressQueue
= CFArrayCreateMutable(CFGetAllocator(s
), 0, &kCFTypeArrayCallBacks
);
1259 CFArrayAppendValue(s
->_dataQueue
, (void *)(uintptr_t)sock
);
1260 CFArrayAppendValue(s
->_addressQueue
, address
);
1262 if ((s
->_f
.client
& kCFSocketAcceptCallBack
) != 0 && (s
->_f
.disabled
& kCFSocketAcceptCallBack
) == 0
1263 && __CFSocketIsScheduled(s
)
1265 __CFSpinLock(&__CFActiveSocketsLock
);
1266 /* restore socket to fds */
1267 __CFSocketSetFDForRead(s
);
1268 __CFSpinUnlock(&__CFActiveSocketsLock
);
1272 if (!__CFSocketIsValid(s
) || (s
->_f
.disabled
& kCFSocketReadCallBack
) != 0) {
1273 __CFSocketUnlock(s
);
1277 if (causedByTimeout
) {
1278 #if defined(LOG_CFSOCKET)
1279 fprintf(stdout
, "TIMEOUT RECEIVED - WILL SIGNAL IMMEDIATELY TO FLUSH (%d buffered)\n", s
->_bytesToBufferPos
);
1281 /* we've got a timeout, but no bytes read. Ignore the timeout. */
1282 if (s
->_bytesToBufferPos
== 0) {
1283 #if defined(LOG_CFSOCKET)
1284 fprintf(stdout
, "TIMEOUT - but no bytes, restoring to active set\n");
1288 __CFSpinLock(&__CFActiveSocketsLock
);
1289 /* restore socket to fds */
1290 __CFSocketSetFDForRead(s
);
1291 __CFSpinUnlock(&__CFActiveSocketsLock
);
1292 __CFSocketUnlock(s
);
1295 } else if (s
->_bytesToBuffer
!= 0 && ! s
->_atEOF
) {
1298 CFIndex ctRemaining
= s
->_bytesToBuffer
- s
->_bytesToBufferPos
;
1300 /* if our buffer has room, we go ahead and buffer */
1301 if (ctRemaining
> 0) {
1302 base
= CFDataGetMutableBytePtr(s
->_readBuffer
);
1305 ctRead
= read(CFSocketGetNative(s
), &base
[s
->_bytesToBufferPos
], ctRemaining
);
1306 } while (ctRead
== -1 && errno
== EAGAIN
);
1310 s
->_bufferedReadError
= errno
;
1312 #if defined(LOG_CFSOCKET)
1313 fprintf(stderr
, "BUFFERED READ GOT ERROR %d\n", errno
);
1318 #if defined(LOG_CFSOCKET)
1319 fprintf(stdout
, "DONE READING (EOF) - GOING TO SIGNAL\n");
1325 s
->_bytesToBufferPos
+= ctRead
;
1326 if (s
->_bytesToBuffer
!= s
->_bytesToBufferPos
) {
1327 #if defined(LOG_CFSOCKET)
1328 fprintf(stdout
, "READ %d - need %d MORE - GOING BACK FOR MORE\n", ctRead
, s
->_bytesToBuffer
- s
->_bytesToBufferPos
);
1330 __CFSpinLock(&__CFActiveSocketsLock
);
1331 /* restore socket to fds */
1332 __CFSocketSetFDForRead(s
);
1333 __CFSpinUnlock(&__CFActiveSocketsLock
);
1334 __CFSocketUnlock(s
);
1337 #if defined(LOG_CFSOCKET)
1338 fprintf(stdout
, "DONE READING (read %d bytes) - GOING TO SIGNAL\n", ctRead
);
1345 __CFSocketSetReadSignalled(s
);
1347 #if defined(LOG_CFSOCKET)
1348 fprintf(stdout
, "read signaling source for socket %d\n", s
->_socket
);
1350 CFRunLoopSourceSignal(s
->_source0
);
1351 CFRunLoopRef rl
= __CFSocketCopyRunLoopToWakeUp(s
);
1352 __CFSocketUnlock(s
);
1354 CFRunLoopWakeUp(rl
);
1359 static struct timeval
* intervalToTimeval(CFTimeInterval timeout
, struct timeval
* tv
)
1364 tv
->tv_sec
= (0 >= timeout
|| INT_MAX
<= timeout
) ? INT_MAX
: (int)(float)floor(timeout
);
1365 tv
->tv_usec
= (int)((timeout
- floor(timeout
)) * 1.0E6
);
1370 /* note that this returns a pointer to the min value, which won't have changed during
1371 the dictionary apply, since we've got the active sockets lock held */
1372 static void _calcMinTimeout_locked(const void* val
, void* ctxt
)
1374 CFSocketRef s
= (CFSocketRef
) val
;
1375 struct timeval
** minTime
= (struct timeval
**) ctxt
;
1376 if (timerisset(&s
->_readBufferTimeout
) && (*minTime
== NULL
|| timercmp(&s
->_readBufferTimeout
, *minTime
, <)))
1377 *minTime
= &s
->_readBufferTimeout
;
1378 else if (s
->_leftoverBytes
) {
1379 /* If there's anyone with leftover bytes, they'll need to be awoken immediately */
1380 static struct timeval sKickerTime
= { 0, 0 };
1381 *minTime
= &sKickerTime
;
1385 void __CFSocketSetSocketReadBufferAttrs(CFSocketRef s
, CFTimeInterval timeout
, CFIndex length
)
1387 struct timeval timeoutVal
;
1389 intervalToTimeval(timeout
, &timeoutVal
);
1391 /* lock ordering is socket lock, activesocketslock */
1392 /* activesocketslock protects our timeout calculation */
1394 __CFSpinLock(&__CFActiveSocketsLock
);
1396 #if defined(LOG_CFSOCKET)
1397 s
->didLogSomething
= false;
1400 if (s
->_bytesToBuffer
!= length
) {
1401 CFIndex ctBuffer
= s
->_bytesToBufferPos
- s
->_bytesToBufferReadPos
;
1404 /* As originally envisaged, you were supposed to be sure to drain the buffer before
1405 * issuing another request on the socket. In practice, there seem to be times when we want to re-use
1406 * the stream (or perhaps, are on our way to closing it out) and this policy doesn't work so well.
1407 * So, if someone changes the buffer size while we have bytes already buffered, we put them
1408 * aside and use them to satisfy any subsequent reads.
1410 #if defined(LOG_CFSOCKET)
1411 __socketLog("%s(%d): WARNING: shouldn't set read buffer length while data (%d bytes) is still in the read buffer (leftover total %d)", __FUNCTION__
, __LINE__
, ctBuffer
, s
->_leftoverBytes
? CFDataGetLength(s
->_leftoverBytes
) : 0);
1414 if (s
->_leftoverBytes
== NULL
)
1415 s
->_leftoverBytes
= CFDataCreateMutable(CFGetAllocator(s
), 0);
1417 /* append the current buffered bytes over. We'll keep draining _leftoverBytes while we have them... */
1418 CFDataAppendBytes(s
->_leftoverBytes
, CFDataGetBytePtr(s
->_readBuffer
) + s
->_bytesToBufferReadPos
, ctBuffer
);
1419 CFRelease(s
->_readBuffer
);
1420 s
->_readBuffer
= NULL
;
1422 s
->_bytesToBuffer
= 0;
1423 s
->_bytesToBufferPos
= 0;
1424 s
->_bytesToBufferReadPos
= 0;
1427 s
->_bytesToBuffer
= 0;
1428 s
->_bytesToBufferPos
= 0;
1429 s
->_bytesToBufferReadPos
= 0;
1430 if (s
->_readBuffer
) {
1431 CFRelease(s
->_readBuffer
);
1432 s
->_readBuffer
= NULL
;
1434 // Zero length buffer, smash the timeout
1435 timeoutVal
= (struct timeval
) { 0, 0 };
1437 /* if the buffer shrank, we can re-use the old one */
1438 if (length
> s
->_bytesToBuffer
) {
1439 if (s
->_readBuffer
) {
1440 CFRelease(s
->_readBuffer
);
1441 s
->_readBuffer
= NULL
;
1445 s
->_bytesToBuffer
= length
;
1446 s
->_bytesToBufferPos
= 0;
1447 s
->_bytesToBufferReadPos
= 0;
1448 if (s
->_readBuffer
== NULL
) {
1449 s
->_readBuffer
= CFDataCreateMutable(kCFAllocatorSystemDefault
, length
);
1450 CFDataSetLength(s
->_readBuffer
, length
);
1455 if (timercmp(&s
->_readBufferTimeout
, &timeoutVal
, !=)) {
1456 s
->_readBufferTimeout
= timeoutVal
;
1457 __CFReadSocketsTimeoutInvalid
= true;
1460 __CFSpinUnlock(&__CFActiveSocketsLock
);
1461 __CFSocketUnlock(s
);
1464 CFIndex
__CFSocketRead(CFSocketRef s
, UInt8
* buffer
, CFIndex length
, int* error
)
1466 #if defined(LOG_CFSOCKET)
1467 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
);
1470 CFIndex result
= -1;
1476 /* Any leftover buffered bytes? */
1477 if (s
->_leftoverBytes
) {
1478 CFIndex ctBuffer
= CFDataGetLength(s
->_leftoverBytes
);
1480 fprintf(stderr
, "%s(%ld): WARNING: Draining %ld leftover bytes first\n\n", __FUNCTION__
, (long)__LINE__
, (long)ctBuffer
);
1482 if (ctBuffer
> length
)
1484 memcpy(buffer
, CFDataGetBytePtr(s
->_leftoverBytes
), ctBuffer
);
1485 if (ctBuffer
< CFDataGetLength(s
->_leftoverBytes
))
1486 CFDataReplaceBytes(s
->_leftoverBytes
, CFRangeMake(0, ctBuffer
), NULL
, 0);
1488 CFRelease(s
->_leftoverBytes
);
1489 s
->_leftoverBytes
= NULL
;
1495 /* return whatever we've buffered */
1496 if (s
->_bytesToBuffer
!= 0) {
1497 CFIndex ctBuffer
= s
->_bytesToBufferPos
- s
->_bytesToBufferReadPos
;
1499 /* drain our buffer first */
1500 if (ctBuffer
> length
)
1502 memcpy(buffer
, CFDataGetBytePtr(s
->_readBuffer
) + s
->_bytesToBufferReadPos
, ctBuffer
);
1503 s
->_bytesToBufferReadPos
+= ctBuffer
;
1504 if (s
->_bytesToBufferReadPos
== s
->_bytesToBufferPos
) {
1505 #if defined(LOG_CFSOCKET)
1506 fprintf(stdout
, "DRAINED BUFFER - SHOULD START BUFFERING AGAIN!\n");
1508 s
->_bytesToBufferPos
= 0;
1509 s
->_bytesToBufferReadPos
= 0;
1512 #if defined(LOG_CFSOCKET)
1513 fprintf(stdout
, "SLURPED %d BYTES FROM BUFFER %d LEFT TO READ!\n", ctBuffer
, length
);
1520 /* nothing buffered, or no buffer selected */
1522 /* Did we get an error on a previous read (or buffered read)? */
1523 if (s
->_bufferedReadError
!= 0) {
1524 #if defined(LOG_CFSOCKET)
1525 fprintf(stdout
, "RETURNING ERROR %d\n", s
->_bufferedReadError
);
1527 *error
= s
->_bufferedReadError
;
1532 /* nothing buffered, if we've hit eof, don't bother reading any more */
1534 #if defined(LOG_CFSOCKET)
1535 fprintf(stdout
, "RETURNING EOF\n");
1542 result
= read(CFSocketGetNative(s
), buffer
, length
);
1543 #if defined(LOG_CFSOCKET)
1544 fprintf(stdout
, "READ %d bytes", result
);
1548 /* note that we hit EOF */
1550 } else if (result
< 0) {
1553 /* if it wasn't EAGAIN, record it (although we shouldn't get called again) */
1554 if (*error
!= EAGAIN
) {
1555 s
->_bufferedReadError
= *error
;
1560 __CFSocketUnlock(s
);
1565 Boolean
__CFSocketGetBytesAvailable(CFSocketRef s
, CFIndex
* ctBytesAvailable
)
1567 CFIndex ctBuffer
= s
->_bytesToBufferPos
- s
->_bytesToBufferReadPos
;
1568 if (ctBuffer
!= 0) {
1569 *ctBytesAvailable
= ctBuffer
;
1573 #if DEPLOYMENT_TARGET_WINDOWS
1574 int bytesAvailable
, intLen
= sizeof(bytesAvailable
);
1575 result
= getsockopt(CFSocketGetNative(s
), SOL_SOCKET
, SO_NREAD
, &bytesAvailable
, (void *)&intLen
);
1577 unsigned long bytesAvailable
;
1578 result
= ioctlsocket(CFSocketGetNative(s
), FIONREAD
, &bytesAvailable
);
1582 *ctBytesAvailable
= (CFIndex
) bytesAvailable
;
1587 #if defined(LOG_CFSOCKET)
1588 static void __CFSocketWriteSocketList(CFArrayRef sockets
, CFDataRef fdSet
, Boolean onlyIfSet
) {
1589 fd_set
*tempfds
= (fd_set
*)CFDataGetBytePtr(fdSet
);
1591 for (idx
= 0, cnt
= CFArrayGetCount(sockets
); idx
< cnt
; idx
++) {
1592 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(sockets
, idx
);
1593 if (FD_ISSET(s
->_socket
, tempfds
)) {
1594 fprintf(stdout
, "%d ", s
->_socket
);
1595 } else if (!onlyIfSet
) {
1596 fprintf(stdout
, "(%d) ", s
->_socket
);
1603 __attribute__ ((noreturn
)) // mostly interesting for shutting up a warning
1604 #endif /* __GNUC__ */
1605 static void __CFSocketManager(void * arg
)
1607 if (objc_collectingEnabled()) auto_zone_register_thread(auto_zone());
1608 SInt32 nrfds
, maxnrfds
, fdentries
= 1;
1610 fd_set
*exceptfds
= NULL
;
1611 fd_set
*writefds
= (fd_set
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, fdentries
* sizeof(fd_mask
), 0);
1612 fd_set
*readfds
= (fd_set
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, fdentries
* sizeof(fd_mask
), 0);
1615 uint8_t buffer
[256];
1616 CFMutableArrayRef selectedWriteSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
1617 CFMutableArrayRef selectedReadSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
1618 CFIndex selectedWriteSocketsIndex
= 0, selectedReadSocketsIndex
= 0;
1621 struct timeval
* pTimeout
= NULL
;
1622 struct timeval timeBeforeSelect
;
1625 __CFSpinLock(&__CFActiveSocketsLock
);
1626 __CFSocketManagerIteration
++;
1627 #if defined(LOG_CFSOCKET)
1628 fprintf(stdout
, "socket manager iteration %lu looking at read sockets ", __CFSocketManagerIteration
);
1629 __CFSocketWriteSocketList(__CFReadSockets
, __CFReadSocketsFds
, FALSE
);
1630 if (0 < CFArrayGetCount(__CFWriteSockets
)) {
1631 fprintf(stdout
, " and write sockets ");
1632 __CFSocketWriteSocketList(__CFWriteSockets
, __CFWriteSocketsFds
, FALSE
);
1634 fprintf(stdout
, "\n");
1636 rfds
= __CFSocketFdGetSize(__CFReadSocketsFds
);
1637 wfds
= __CFSocketFdGetSize(__CFWriteSocketsFds
);
1638 maxnrfds
= __CFMax(rfds
, wfds
);
1639 if (maxnrfds
> fdentries
* (int)NFDBITS
) {
1640 fdentries
= (maxnrfds
+ NFDBITS
- 1) / NFDBITS
;
1641 writefds
= (fd_set
*)CFAllocatorReallocate(kCFAllocatorSystemDefault
, writefds
, fdentries
* sizeof(fd_mask
), 0);
1642 readfds
= (fd_set
*)CFAllocatorReallocate(kCFAllocatorSystemDefault
, readfds
, fdentries
* sizeof(fd_mask
), 0);
1644 memset(writefds
, 0, fdentries
* sizeof(fd_mask
));
1645 memset(readfds
, 0, fdentries
* sizeof(fd_mask
));
1646 CFDataGetBytes(__CFWriteSocketsFds
, CFRangeMake(0, CFDataGetLength(__CFWriteSocketsFds
)), (UInt8
*)writefds
);
1647 CFDataGetBytes(__CFReadSocketsFds
, CFRangeMake(0, CFDataGetLength(__CFReadSocketsFds
)), (UInt8
*)readfds
);
1649 if (__CFReadSocketsTimeoutInvalid
) {
1650 struct timeval
* minTimeout
= NULL
;
1651 __CFReadSocketsTimeoutInvalid
= false;
1652 #if defined(LOG_CFSOCKET)
1653 fprintf(stdout
, "Figuring out which sockets have timeouts...\n");
1655 CFArrayApplyFunction(__CFReadSockets
, CFRangeMake(0, CFArrayGetCount(__CFReadSockets
)), _calcMinTimeout_locked
, (void*) &minTimeout
);
1657 if (minTimeout
== NULL
) {
1658 #if defined(LOG_CFSOCKET)
1659 fprintf(stdout
, "No one wants a timeout!\n");
1663 #if defined(LOG_CFSOCKET)
1664 fprintf(stdout
, "timeout will be %d, %d!\n", minTimeout
->tv_sec
, minTimeout
->tv_usec
);
1672 #if defined(LOG_CFSOCKET)
1673 fprintf(stdout
, "select will have a %d, %d timeout\n", pTimeout
->tv_sec
, pTimeout
->tv_usec
);
1675 gettimeofday(&timeBeforeSelect
, NULL
);
1678 __CFSpinUnlock(&__CFActiveSocketsLock
);
1680 nrfds
= select(maxnrfds
, readfds
, writefds
, exceptfds
, pTimeout
);
1682 #if defined(LOG_CFSOCKET)
1683 fprintf(stdout
, "socket manager woke from select, ret=%ld\n", nrfds
);
1687 * select returned a timeout
1690 struct timeval timeAfterSelect
;
1691 struct timeval deltaTime
;
1692 gettimeofday(&timeAfterSelect
, NULL
);
1693 /* timeBeforeSelect becomes the delta */
1694 timersub(&timeAfterSelect
, &timeBeforeSelect
, &deltaTime
);
1696 #if defined(LOG_CFSOCKET)
1697 fprintf(stdout
, "Socket manager received timeout - kicking off expired reads (expired delta %d, %d)\n", deltaTime
.tv_sec
, deltaTime
.tv_usec
);
1700 __CFSpinLock(&__CFActiveSocketsLock
);
1703 cnt
= CFArrayGetCount(__CFReadSockets
);
1704 for (idx
= 0; idx
< cnt
; idx
++) {
1705 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFReadSockets
, idx
);
1706 if (timerisset(&s
->_readBufferTimeout
) || s
->_leftoverBytes
) {
1707 CFSocketNativeHandle sock
= s
->_socket
;
1708 // We might have an new element in __CFReadSockets that we weren't listening to,
1709 // in which case we must be sure not to test a bit in the fdset that is
1710 // outside our mask size.
1711 Boolean sockInBounds
= (0 <= sock
&& sock
< maxnrfds
);
1712 /* if this sockets timeout is less than or equal elapsed time, then signal it */
1713 if (INVALID_SOCKET
!= sock
&& sockInBounds
) {
1714 #if defined(LOG_CFSOCKET)
1715 fprintf(stdout
, "Expiring socket %d (delta %d, %d)\n", sock
, s
->_readBufferTimeout
.tv_sec
, s
->_readBufferTimeout
.tv_usec
);
1717 CFArraySetValueAtIndex(selectedReadSockets
, selectedReadSocketsIndex
, s
);
1718 selectedReadSocketsIndex
++;
1719 /* socket is removed from fds here, will be restored in read handling or in perform function */
1720 if (!tempfds
) tempfds
= (fd_set
*)CFDataGetMutableBytePtr(__CFReadSocketsFds
);
1721 FD_CLR(sock
, tempfds
);
1726 __CFSpinUnlock(&__CFActiveSocketsLock
);
1728 /* and below, we dispatch through the normal read dispatch mechanism */
1732 SInt32 selectError
= __CFSocketLastError();
1733 #if defined(LOG_CFSOCKET)
1734 fprintf(stdout
, "socket manager received error %ld from select\n", selectError
);
1736 if (EBADF
== selectError
) {
1737 CFMutableArrayRef invalidSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
1738 __CFSpinLock(&__CFActiveSocketsLock
);
1739 cnt
= CFArrayGetCount(__CFWriteSockets
);
1740 for (idx
= 0; idx
< cnt
; idx
++) {
1741 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFWriteSockets
, idx
);
1742 if (!__CFNativeSocketIsValid(s
->_socket
)) {
1743 #if defined(LOG_CFSOCKET)
1744 fprintf(stdout
, "socket manager found write socket %d invalid\n", s
->_socket
);
1746 CFArrayAppendValue(invalidSockets
, s
);
1749 cnt
= CFArrayGetCount(__CFReadSockets
);
1750 for (idx
= 0; idx
< cnt
; idx
++) {
1751 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFReadSockets
, idx
);
1752 if (!__CFNativeSocketIsValid(s
->_socket
)) {
1753 #if defined(LOG_CFSOCKET)
1754 fprintf(stdout
, "socket manager found read socket %d invalid\n", s
->_socket
);
1756 CFArrayAppendValue(invalidSockets
, s
);
1759 __CFSpinUnlock(&__CFActiveSocketsLock
);
1761 cnt
= CFArrayGetCount(invalidSockets
);
1762 for (idx
= 0; idx
< cnt
; idx
++) {
1763 CFSocketInvalidate(((CFSocketRef
)CFArrayGetValueAtIndex(invalidSockets
, idx
)));
1765 CFRelease(invalidSockets
);
1769 if (FD_ISSET(__CFWakeupSocketPair
[1], readfds
)) {
1770 recv(__CFWakeupSocketPair
[1], buffer
, sizeof(buffer
), 0);
1771 #if defined(LOG_CFSOCKET)
1772 fprintf(stdout
, "socket manager received %c on wakeup socket\n", buffer
[0]);
1775 __CFSpinLock(&__CFActiveSocketsLock
);
1777 cnt
= CFArrayGetCount(__CFWriteSockets
);
1778 for (idx
= 0; idx
< cnt
; idx
++) {
1779 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFWriteSockets
, idx
);
1780 CFSocketNativeHandle sock
= s
->_socket
;
1781 // We might have an new element in __CFWriteSockets that we weren't listening to,
1782 // in which case we must be sure not to test a bit in the fdset that is
1783 // outside our mask size.
1784 Boolean sockInBounds
= (0 <= sock
&& sock
< maxnrfds
);
1785 if (INVALID_SOCKET
!= sock
&& sockInBounds
) {
1786 if (FD_ISSET(sock
, writefds
)) {
1787 CFArraySetValueAtIndex(selectedWriteSockets
, selectedWriteSocketsIndex
, s
);
1788 selectedWriteSocketsIndex
++;
1789 /* socket is removed from fds here, restored by CFSocketReschedule */
1790 if (!tempfds
) tempfds
= (fd_set
*)CFDataGetMutableBytePtr(__CFWriteSocketsFds
);
1791 FD_CLR(sock
, tempfds
);
1792 // CFLog(5, CFSTR("Manager: cleared socket %p from write fds"), s);
1797 cnt
= CFArrayGetCount(__CFReadSockets
);
1798 for (idx
= 0; idx
< cnt
; idx
++) {
1799 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFReadSockets
, idx
);
1800 CFSocketNativeHandle sock
= s
->_socket
;
1801 // We might have an new element in __CFReadSockets that we weren't listening to,
1802 // in which case we must be sure not to test a bit in the fdset that is
1803 // outside our mask size.
1804 Boolean sockInBounds
= (0 <= sock
&& sock
< maxnrfds
);
1805 if (INVALID_SOCKET
!= sock
&& sockInBounds
&& FD_ISSET(sock
, readfds
)) {
1806 CFArraySetValueAtIndex(selectedReadSockets
, selectedReadSocketsIndex
, s
);
1807 selectedReadSocketsIndex
++;
1808 /* socket is removed from fds here, will be restored in read handling or in perform function */
1809 if (!tempfds
) tempfds
= (fd_set
*)CFDataGetMutableBytePtr(__CFReadSocketsFds
);
1810 FD_CLR(sock
, tempfds
);
1813 __CFSpinUnlock(&__CFActiveSocketsLock
);
1815 for (idx
= 0; idx
< selectedWriteSocketsIndex
; idx
++) {
1816 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(selectedWriteSockets
, idx
);
1817 if (kCFNull
== (CFNullRef
)s
) continue;
1818 #if defined(LOG_CFSOCKET)
1819 fprintf(stdout
, "socket manager signaling socket %d for write\n", s
->_socket
);
1821 __CFSocketHandleWrite(s
, FALSE
);
1822 CFArraySetValueAtIndex(selectedWriteSockets
, idx
, kCFNull
);
1824 selectedWriteSocketsIndex
= 0;
1826 for (idx
= 0; idx
< selectedReadSocketsIndex
; idx
++) {
1827 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(selectedReadSockets
, idx
);
1828 if (kCFNull
== (CFNullRef
)s
) continue;
1829 #if defined(LOG_CFSOCKET)
1830 fprintf(stdout
, "socket manager signaling socket %d for read\n", s
->_socket
);
1832 __CFSocketHandleRead(s
, nrfds
== 0);
1833 CFArraySetValueAtIndex(selectedReadSockets
, idx
, kCFNull
);
1835 selectedReadSocketsIndex
= 0;
1837 if (objc_collectingEnabled()) auto_zone_unregister_thread(auto_zone());
1840 static CFStringRef
__CFSocketCopyDescription(CFTypeRef cf
) {
1841 CFSocketRef s
= (CFSocketRef
)cf
;
1842 CFMutableStringRef result
;
1843 CFStringRef contextDesc
= NULL
;
1844 void *contextInfo
= NULL
;
1845 CFStringRef (*contextCopyDescription
)(const void *info
) = NULL
;
1846 result
= CFStringCreateMutable(CFGetAllocator(s
), 0);
1848 void *addr
= s
->_callout
;
1850 const char *name
= (dladdr(addr
, &info
) && info
.dli_saddr
== addr
&& info
.dli_sname
) ? info
.dli_sname
: "???";
1851 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
);
1852 contextInfo
= s
->_context
.info
;
1853 contextCopyDescription
= s
->_context
.copyDescription
;
1854 __CFSocketUnlock(s
);
1855 if (NULL
!= contextInfo
&& NULL
!= contextCopyDescription
) {
1856 contextDesc
= (CFStringRef
)contextCopyDescription(contextInfo
);
1858 if (NULL
== contextDesc
) {
1859 contextDesc
= CFStringCreateWithFormat(CFGetAllocator(s
), NULL
, CFSTR("<CFSocket context %p>"), contextInfo
);
1861 CFStringAppend(result
, contextDesc
);
1862 CFStringAppend(result
, CFSTR("}"));
1863 CFRelease(contextDesc
);
1867 static void __CFSocketDeallocate(CFTypeRef cf
) {
1868 /* Since CFSockets are cached, we can only get here sometime after being invalidated */
1869 CFSocketRef s
= (CFSocketRef
)cf
;
1870 if (NULL
!= s
->_address
) {
1871 CFRelease(s
->_address
);
1874 if (NULL
!= s
->_readBuffer
) {
1875 CFRelease(s
->_readBuffer
);
1876 s
->_readBuffer
= NULL
;
1878 if (NULL
!= s
->_leftoverBytes
) {
1879 CFRelease(s
->_leftoverBytes
);
1880 s
->_leftoverBytes
= NULL
;
1882 timerclear(&s
->_readBufferTimeout
);
1883 s
->_bytesToBuffer
= 0;
1884 s
->_bytesToBufferPos
= 0;
1885 s
->_bytesToBufferReadPos
= 0;
1887 s
->_bufferedReadError
= 0;
1890 static CFTypeID __kCFSocketTypeID
= _kCFRuntimeNotATypeID
;
1892 static const CFRuntimeClass __CFSocketClass
= {
1897 __CFSocketDeallocate
,
1901 __CFSocketCopyDescription
1904 CFTypeID
CFSocketGetTypeID(void) {
1905 if (_kCFRuntimeNotATypeID
== __kCFSocketTypeID
) {
1906 __kCFSocketTypeID
= _CFRuntimeRegisterClass(&__CFSocketClass
);
1908 int ret1
= getrlimit(RLIMIT_NOFILE
, &lim1
);
1909 int mib
[] = {CTL_KERN
, KERN_MAXFILESPERPROC
};
1911 size_t len
= sizeof(int);
1912 int ret0
= sysctl(mib
, 2, &maxfd
, &len
, NULL
, 0);
1913 if (0 == ret0
&& 0 == ret1
&& lim1
.rlim_max
< maxfd
) maxfd
= lim1
.rlim_max
;
1914 if (0 == ret1
&& lim1
.rlim_cur
< maxfd
) {
1915 struct rlimit lim2
= lim1
;
1916 lim2
.rlim_cur
+= 2304;
1917 if (maxfd
< lim2
.rlim_cur
) lim2
.rlim_cur
= maxfd
;
1918 setrlimit(RLIMIT_NOFILE
, &lim2
);
1919 // we try, but do not go to extraordinary measures
1922 return __kCFSocketTypeID
;
1925 static CFSocketRef
_CFSocketCreateWithNative(CFAllocatorRef allocator
, CFSocketNativeHandle sock
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
, Boolean useExistingInstance
) {
1928 int typeSize
= sizeof(memory
->_socketType
);
1929 __CFSpinLock(&__CFActiveSocketsLock
);
1930 if (NULL
== __CFReadSockets
) __CFSocketInitializeSockets();
1931 __CFSpinUnlock(&__CFActiveSocketsLock
);
1932 __CFSpinLock(&__CFAllSocketsLock
);
1933 if (NULL
== __CFAllSockets
) {
1934 __CFAllSockets
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, &kCFTypeDictionaryValueCallBacks
);
1936 if (INVALID_SOCKET
!= sock
&& CFDictionaryGetValueIfPresent(__CFAllSockets
, (void *)(uintptr_t)sock
, (const void **)&memory
)) {
1937 if (useExistingInstance
) {
1938 __CFSpinUnlock(&__CFAllSocketsLock
);
1942 #if defined(LOG_CFSOCKET)
1943 fprintf(stdout
, "useExistingInstance is FALSE, removing existing instance %d from __CFAllSockets\n", (int)memory
);
1945 __CFSpinUnlock(&__CFAllSocketsLock
);
1946 CFSocketInvalidate(memory
);
1947 __CFSpinLock(&__CFAllSocketsLock
);
1950 memory
= (CFSocketRef
)_CFRuntimeCreateInstance(allocator
, CFSocketGetTypeID(), sizeof(struct __CFSocket
) - sizeof(CFRuntimeBase
), NULL
);
1951 if (NULL
== memory
) {
1952 __CFSpinUnlock(&__CFAllSocketsLock
);
1955 __CFSocketSetCallBackTypes(memory
, callBackTypes
);
1956 if (INVALID_SOCKET
!= sock
) __CFSocketSetValid(memory
);
1957 __CFSocketUnsetWriteSignalled(memory
);
1958 __CFSocketUnsetReadSignalled(memory
);
1959 memory
->_f
.client
= ((callBackTypes
& (~kCFSocketConnectCallBack
)) & (~kCFSocketWriteCallBack
)) | kCFSocketCloseOnInvalidate
;
1960 memory
->_f
.disabled
= 0;
1961 memory
->_f
.connected
= FALSE
;
1962 memory
->_f
.writableHint
= FALSE
;
1963 memory
->_f
.closeSignaled
= FALSE
;
1964 memory
->_lock
= CFSpinLockInit
;
1965 memory
->_writeLock
= CFSpinLockInit
;
1966 memory
->_socket
= sock
;
1967 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
1968 memory
->_errorCode
= 0;
1969 memory
->_address
= NULL
;
1970 memory
->_peerAddress
= NULL
;
1971 memory
->_socketSetCount
= 0;
1972 memory
->_source0
= NULL
;
1973 if (INVALID_SOCKET
!= sock
) {
1974 memory
->_runLoops
= CFArrayCreateMutable(allocator
, 0, NULL
);
1976 memory
->_runLoops
= NULL
;
1978 memory
->_callout
= callout
;
1979 memory
->_dataQueue
= NULL
;
1980 memory
->_addressQueue
= NULL
;
1981 memory
->_context
.info
= 0;
1982 memory
->_context
.retain
= 0;
1983 memory
->_context
.release
= 0;
1984 memory
->_context
.copyDescription
= 0;
1985 timerclear(&memory
->_readBufferTimeout
);
1986 memory
->_readBuffer
= NULL
;
1987 memory
->_bytesToBuffer
= 0;
1988 memory
->_bytesToBufferPos
= 0;
1989 memory
->_bytesToBufferReadPos
= 0;
1990 memory
->_atEOF
= false;
1991 memory
->_bufferedReadError
= 0;
1992 memory
->_leftoverBytes
= NULL
;
1994 if (INVALID_SOCKET
!= sock
) CFDictionaryAddValue(__CFAllSockets
, (void *)(uintptr_t)sock
, memory
);
1995 __CFSpinUnlock(&__CFAllSocketsLock
);
1996 if (NULL
!= context
) {
1997 void *contextInfo
= context
->retain
? (void *)context
->retain(context
->info
) : context
->info
;
1998 __CFSocketLock(memory
);
1999 memory
->_context
.retain
= context
->retain
;
2000 memory
->_context
.release
= context
->release
;
2001 memory
->_context
.copyDescription
= context
->copyDescription
;
2002 memory
->_context
.info
= contextInfo
;
2003 __CFSocketUnlock(memory
);
2005 // CFLog(5, CFSTR("CFSocketCreateWithNative(): created socket %p with callbacks 0x%x"), memory, callBackTypes);
2009 CFSocketRef
CFSocketCreateWithNative(CFAllocatorRef allocator
, CFSocketNativeHandle sock
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
) {
2010 return _CFSocketCreateWithNative(allocator
, sock
, callBackTypes
, callout
, context
, TRUE
);
2013 void CFSocketInvalidate(CFSocketRef s
) {
2014 // CFLog(5, CFSTR("CFSocketInvalidate(%p) starting"), s);
2016 UInt32 previousSocketManagerIteration
;
2017 __CFGenericValidateType(s
, CFSocketGetTypeID());
2018 #if defined(LOG_CFSOCKET)
2019 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
);
2022 __CFSpinLock(&__CFAllSocketsLock
);
2024 if (__CFSocketIsValid(s
)) {
2026 CFRunLoopSourceRef source0
;
2027 void *contextInfo
= NULL
;
2028 void (*contextRelease
)(const void *info
) = NULL
;
2029 __CFSocketUnsetValid(s
);
2030 __CFSocketUnsetWriteSignalled(s
);
2031 __CFSocketUnsetReadSignalled(s
);
2032 __CFSpinLock(&__CFActiveSocketsLock
);
2033 idx
= CFArrayGetFirstIndexOfValue(__CFWriteSockets
, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets
)), s
);
2035 CFArrayRemoveValueAtIndex(__CFWriteSockets
, idx
);
2036 __CFSocketClearFDForWrite(s
);
2038 // No need to clear FD's for V1 sources, since we'll just throw the whole event away
2039 idx
= CFArrayGetFirstIndexOfValue(__CFReadSockets
, CFRangeMake(0, CFArrayGetCount(__CFReadSockets
)), s
);
2041 CFArrayRemoveValueAtIndex(__CFReadSockets
, idx
);
2042 __CFSocketClearFDForRead(s
);
2044 previousSocketManagerIteration
= __CFSocketManagerIteration
;
2045 __CFSpinUnlock(&__CFActiveSocketsLock
);
2046 CFDictionaryRemoveValue(__CFAllSockets
, (void *)(uintptr_t)(s
->_socket
));
2047 if ((s
->_f
.client
& kCFSocketCloseOnInvalidate
) != 0) closesocket(s
->_socket
);
2048 s
->_socket
= INVALID_SOCKET
;
2049 if (NULL
!= s
->_peerAddress
) {
2050 CFRelease(s
->_peerAddress
);
2051 s
->_peerAddress
= NULL
;
2053 if (NULL
!= s
->_dataQueue
) {
2054 CFRelease(s
->_dataQueue
);
2055 s
->_dataQueue
= NULL
;
2057 if (NULL
!= s
->_addressQueue
) {
2058 CFRelease(s
->_addressQueue
);
2059 s
->_addressQueue
= NULL
;
2061 s
->_socketSetCount
= 0;
2062 for (idx
= CFArrayGetCount(s
->_runLoops
); idx
--;) {
2063 CFRunLoopWakeUp((CFRunLoopRef
)CFArrayGetValueAtIndex(s
->_runLoops
, idx
));
2065 CFRelease(s
->_runLoops
);
2066 s
->_runLoops
= NULL
;
2067 source0
= s
->_source0
;
2069 contextInfo
= s
->_context
.info
;
2070 contextRelease
= s
->_context
.release
;
2071 s
->_context
.info
= 0;
2072 s
->_context
.retain
= 0;
2073 s
->_context
.release
= 0;
2074 s
->_context
.copyDescription
= 0;
2075 __CFSocketUnlock(s
);
2076 if (NULL
!= contextRelease
) {
2077 contextRelease(contextInfo
);
2079 if (NULL
!= source0
) {
2080 CFRunLoopSourceInvalidate(source0
);
2084 __CFSocketUnlock(s
);
2086 __CFSpinUnlock(&__CFAllSocketsLock
);
2088 // CFLog(5, CFSTR("CFSocketInvalidate(%p) done"), s);
2091 Boolean
CFSocketIsValid(CFSocketRef s
) {
2093 __CFGenericValidateType(s
, CFSocketGetTypeID());
2094 return __CFSocketIsValid(s
);
2097 CFSocketNativeHandle
CFSocketGetNative(CFSocketRef s
) {
2099 __CFGenericValidateType(s
, CFSocketGetTypeID());
2103 CFDataRef
CFSocketCopyAddress(CFSocketRef s
) {
2105 CFDataRef result
= NULL
;
2106 __CFGenericValidateType(s
, CFSocketGetTypeID());
2108 __CFSocketEstablishAddress(s
);
2109 if (NULL
!= s
->_address
) {
2110 result
= CFRetain(s
->_address
);
2112 __CFSocketUnlock(s
);
2113 // CFLog(5, CFSTR("CFSocketCopyAddress(): created socket %p address %@"), s, result);
2117 CFDataRef
CFSocketCopyPeerAddress(CFSocketRef s
) {
2119 CFDataRef result
= NULL
;
2120 __CFGenericValidateType(s
, CFSocketGetTypeID());
2122 __CFSocketEstablishPeerAddress(s
);
2123 if (NULL
!= s
->_peerAddress
) {
2124 result
= CFRetain(s
->_peerAddress
);
2126 __CFSocketUnlock(s
);
2127 // CFLog(5, CFSTR("CFSocketCopyAddress(): created socket %p peer address %@"), s, result);
2131 void CFSocketGetContext(CFSocketRef s
, CFSocketContext
*context
) {
2133 __CFGenericValidateType(s
, CFSocketGetTypeID());
2134 CFAssert1(0 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__
);
2135 *context
= s
->_context
;
2138 CFOptionFlags
CFSocketGetSocketFlags(CFSocketRef s
) {
2140 __CFGenericValidateType(s
, CFSocketGetTypeID());
2141 return s
->_f
.client
;
2144 void CFSocketSetSocketFlags(CFSocketRef s
, CFOptionFlags flags
) {
2146 __CFGenericValidateType(s
, CFSocketGetTypeID());
2148 #if defined(LOG_CFSOCKET)
2149 fprintf(stdout
, "setting flags for socket %d, from 0x%x to 0x%lx\n", s
->_socket
, s
->_f
.client
, flags
);
2151 s
->_f
.client
= flags
;
2152 __CFSocketUnlock(s
);
2153 // CFLog(5, CFSTR("CFSocketSetSocketFlags(%p, 0x%x)"), s, flags);
2156 void CFSocketDisableCallBacks(CFSocketRef s
, CFOptionFlags callBackTypes
) {
2158 Boolean wakeup
= false;
2159 uint8_t readCallBackType
;
2160 __CFGenericValidateType(s
, CFSocketGetTypeID());
2162 if (__CFSocketIsValid(s
) && __CFSocketIsScheduled(s
)) {
2163 callBackTypes
&= __CFSocketCallBackTypes(s
);
2164 readCallBackType
= __CFSocketReadCallBackType(s
);
2165 s
->_f
.disabled
|= callBackTypes
;
2166 #if defined(LOG_CFSOCKET)
2167 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
);
2169 __CFSpinLock(&__CFActiveSocketsLock
);
2170 if ((readCallBackType
== kCFSocketAcceptCallBack
) || !__CFSocketIsConnectionOriented(s
)) s
->_f
.connected
= TRUE
;
2171 if (((callBackTypes
& kCFSocketWriteCallBack
) != 0) || (((callBackTypes
& kCFSocketConnectCallBack
) != 0) && !s
->_f
.connected
)) {
2172 if (__CFSocketClearFDForWrite(s
)) {
2173 // do not wake up the socket manager thread if all relevant write callbacks are disabled
2174 CFOptionFlags writeCallBacksAvailable
= __CFSocketCallBackTypes(s
) & (kCFSocketWriteCallBack
| kCFSocketConnectCallBack
);
2175 if (s
->_f
.connected
) writeCallBacksAvailable
&= ~kCFSocketConnectCallBack
;
2176 if ((s
->_f
.disabled
& writeCallBacksAvailable
) != writeCallBacksAvailable
) wakeup
= true;
2179 if (readCallBackType
!= kCFSocketNoCallBack
&& (callBackTypes
& readCallBackType
) != 0) {
2180 if (__CFSocketClearFDForRead(s
)) {
2181 // do not wake up the socket manager thread if callback type is read
2182 if (readCallBackType
!= kCFSocketReadCallBack
) wakeup
= true;
2185 __CFSpinUnlock(&__CFActiveSocketsLock
);
2187 __CFSocketUnlock(s
);
2188 if (wakeup
&& __CFSocketManagerThread
) {
2190 send(__CFWakeupSocketPair
[0], &c
, sizeof(c
), 0);
2194 // "force" means to clear the disabled bits set by DisableCallBacks and always reenable.
2195 // if (!force) we respect those bits, meaning they may stop us from enabling.
2196 // In addition, if !force we assume that the sockets have already been added to the
2197 // __CFReadSockets and __CFWriteSockets arrays. This is true because the callbacks start
2198 // enabled when the CFSocket is created (at which time we enable with force).
2199 // Called with SocketLock held, returns with it released!
2200 void __CFSocketEnableCallBacks(CFSocketRef s
, CFOptionFlags callBackTypes
, Boolean force
, uint8_t wakeupChar
) {
2202 Boolean wakeup
= FALSE
;
2203 if (!callBackTypes
) {
2204 __CFSocketUnlock(s
);
2207 if (__CFSocketIsValid(s
) && __CFSocketIsScheduled(s
)) {
2208 Boolean turnOnWrite
= FALSE
, turnOnConnect
= FALSE
, turnOnRead
= FALSE
;
2209 uint8_t readCallBackType
= __CFSocketReadCallBackType(s
);
2210 callBackTypes
&= __CFSocketCallBackTypes(s
);
2211 if (force
) s
->_f
.disabled
&= ~callBackTypes
;
2212 #if defined(LOG_CFSOCKET)
2213 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
);
2215 /* We will wait for connection only for connection-oriented, non-rendezvous sockets that are not already connected. Mark others as already connected. */
2216 if ((readCallBackType
== kCFSocketAcceptCallBack
) || !__CFSocketIsConnectionOriented(s
)) s
->_f
.connected
= TRUE
;
2218 // First figure out what to turn on
2219 if (s
->_f
.connected
|| (callBackTypes
& kCFSocketConnectCallBack
) == 0) {
2220 // if we want write callbacks and they're not disabled...
2221 if ((callBackTypes
& kCFSocketWriteCallBack
) != 0 && (s
->_f
.disabled
& kCFSocketWriteCallBack
) == 0) turnOnWrite
= TRUE
;
2223 // if we want connect callbacks and they're not disabled...
2224 if ((callBackTypes
& kCFSocketConnectCallBack
) != 0 && (s
->_f
.disabled
& kCFSocketConnectCallBack
) == 0) turnOnConnect
= TRUE
;
2226 // if we want read callbacks and they're not disabled...
2227 if (readCallBackType
!= kCFSocketNoCallBack
&& (callBackTypes
& readCallBackType
) != 0 && (s
->_f
.disabled
& kCFSocketReadCallBack
) == 0) turnOnRead
= TRUE
;
2229 // Now turn on the callbacks we've determined that we want on
2230 if (turnOnRead
|| turnOnWrite
|| turnOnConnect
) {
2231 __CFSpinLock(&__CFActiveSocketsLock
);
2232 if (turnOnWrite
|| turnOnConnect
) {
2234 SInt32 idx
= CFArrayGetFirstIndexOfValue(__CFWriteSockets
, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets
)), s
);
2235 if (kCFNotFound
== idx
) CFArrayAppendValue(__CFWriteSockets
, s
);
2236 // if (kCFNotFound == idx) CFLog(5, CFSTR("__CFSocketEnableCallBacks: put %p in __CFWriteSockets list due to force and non-presence"), s);
2238 if (__CFSocketSetFDForWrite(s
)) wakeup
= true;
2242 SInt32 idx
= CFArrayGetFirstIndexOfValue(__CFReadSockets
, CFRangeMake(0, CFArrayGetCount(__CFReadSockets
)), s
);
2243 if (kCFNotFound
== idx
) CFArrayAppendValue(__CFReadSockets
, s
);
2245 if (__CFSocketSetFDForRead(s
)) wakeup
= true;
2247 if (wakeup
&& NULL
== __CFSocketManagerThread
) __CFSocketManagerThread
= __CFStartSimpleThread(__CFSocketManager
, 0);
2248 __CFSpinUnlock(&__CFActiveSocketsLock
);
2251 __CFSocketUnlock(s
);
2252 if (wakeup
) send(__CFWakeupSocketPair
[0], &wakeupChar
, sizeof(wakeupChar
), 0);
2255 void CFSocketEnableCallBacks(CFSocketRef s
, CFOptionFlags callBackTypes
) {
2257 __CFGenericValidateType(s
, CFSocketGetTypeID());
2259 __CFSocketEnableCallBacks(s
, callBackTypes
, TRUE
, 'r');
2260 // CFLog(5, CFSTR("CFSocketEnableCallBacks(%p, 0x%x) done"), s, callBackTypes);
2263 static void __CFSocketSchedule(void *info
, CFRunLoopRef rl
, CFStringRef mode
) {
2264 CFSocketRef s
= info
;
2266 //??? also need to arrange delivery of all pending data
2267 if (__CFSocketIsValid(s
)) {
2268 CFArrayAppendValue(s
->_runLoops
, rl
);
2269 s
->_socketSetCount
++;
2270 // Since the v0 source is listened to on the SocketMgr thread, no matter how many modes it
2271 // is added to we just need to enable it there once (and _socketSetCount gives us a refCount
2272 // to know when we can finally disable it).
2273 if (1 == s
->_socketSetCount
) {
2274 #if defined(LOG_CFSOCKET)
2275 fprintf(stdout
, "scheduling socket %d\n", s
->_socket
);
2277 // CFLog(5, CFSTR("__CFSocketSchedule(%p, %p, %p)"), s, rl, mode);
2278 __CFSocketEnableCallBacks(s
, __CFSocketCallBackTypes(s
), TRUE
, 's'); // unlocks s
2280 __CFSocketUnlock(s
);
2282 __CFSocketUnlock(s
);
2285 static void __CFSocketCancel(void *info
, CFRunLoopRef rl
, CFStringRef mode
) {
2286 CFSocketRef s
= info
;
2289 s
->_socketSetCount
--;
2290 if (0 == s
->_socketSetCount
) {
2291 __CFSpinLock(&__CFActiveSocketsLock
);
2292 idx
= CFArrayGetFirstIndexOfValue(__CFWriteSockets
, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets
)), s
);
2294 // CFLog(5, CFSTR("__CFSocketCancel: removing %p from __CFWriteSockets list"), s);
2295 CFArrayRemoveValueAtIndex(__CFWriteSockets
, idx
);
2296 __CFSocketClearFDForWrite(s
);
2298 idx
= CFArrayGetFirstIndexOfValue(__CFReadSockets
, CFRangeMake(0, CFArrayGetCount(__CFReadSockets
)), s
);
2300 CFArrayRemoveValueAtIndex(__CFReadSockets
, idx
);
2301 __CFSocketClearFDForRead(s
);
2303 __CFSpinUnlock(&__CFActiveSocketsLock
);
2305 if (NULL
!= s
->_runLoops
) {
2306 idx
= CFArrayGetFirstIndexOfValue(s
->_runLoops
, CFRangeMake(0, CFArrayGetCount(s
->_runLoops
)), rl
);
2307 if (0 <= idx
) CFArrayRemoveValueAtIndex(s
->_runLoops
, idx
);
2309 __CFSocketUnlock(s
);
2312 // Note: must be called with socket lock held, then returns with it released
2313 // Used by both the v0 and v1 RunLoopSource perform routines
2314 static void __CFSocketDoCallback(CFSocketRef s
, CFDataRef data
, CFDataRef address
, CFSocketNativeHandle sock
) {
2315 CFSocketCallBack callout
= NULL
;
2316 void *contextInfo
= NULL
;
2317 SInt32 errorCode
= 0;
2318 Boolean readSignalled
= false, writeSignalled
= false, connectSignalled
= false, calledOut
= false;
2319 uint8_t readCallBackType
, callBackTypes
;
2321 callBackTypes
= __CFSocketCallBackTypes(s
);
2322 readCallBackType
= __CFSocketReadCallBackType(s
);
2323 readSignalled
= __CFSocketIsReadSignalled(s
);
2324 writeSignalled
= __CFSocketIsWriteSignalled(s
);
2325 connectSignalled
= writeSignalled
&& !s
->_f
.connected
;
2326 __CFSocketUnsetReadSignalled(s
);
2327 __CFSocketUnsetWriteSignalled(s
);
2328 callout
= s
->_callout
;
2329 contextInfo
= s
->_context
.info
;
2330 #if defined(LOG_CFSOCKET)
2331 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
);
2333 if (writeSignalled
) {
2334 errorCode
= s
->_errorCode
;
2335 s
->_f
.connected
= TRUE
;
2337 __CFSocketUnlock(s
);
2338 if ((callBackTypes
& kCFSocketConnectCallBack
) != 0) {
2339 if (connectSignalled
&& (!calledOut
|| CFSocketIsValid(s
))) {
2340 // CFLog(5, CFSTR("__CFSocketPerformV0(%p) doing connect callback, error: %d"), s, errorCode);
2342 #if defined(LOG_CFSOCKET)
2343 fprintf(stdout
, "perform calling out error %ld to socket %d\n", errorCode
, s
->_socket
);
2345 if (callout
) callout(s
, kCFSocketConnectCallBack
, NULL
, &errorCode
, contextInfo
);
2348 #if defined(LOG_CFSOCKET)
2349 fprintf(stdout
, "perform calling out connect to socket %d\n", s
->_socket
);
2351 if (callout
) callout(s
, kCFSocketConnectCallBack
, NULL
, NULL
, contextInfo
);
2356 if (kCFSocketDataCallBack
== readCallBackType
) {
2357 if (NULL
!= data
&& (!calledOut
|| CFSocketIsValid(s
))) {
2358 SInt32 datalen
= CFDataGetLength(data
);
2359 #if defined(LOG_CFSOCKET)
2360 fprintf(stdout
, "perform calling out data of length %ld to socket %d\n", datalen
, s
->_socket
);
2362 if (callout
) callout(s
, kCFSocketDataCallBack
, address
, data
, contextInfo
);
2364 if (0 == datalen
) CFSocketInvalidate(s
);
2366 } else if (kCFSocketAcceptCallBack
== readCallBackType
) {
2367 if (INVALID_SOCKET
!= sock
&& (!calledOut
|| CFSocketIsValid(s
))) {
2368 #if defined(LOG_CFSOCKET)
2369 fprintf(stdout
, "perform calling out accept of socket %d to socket %d\n", sock
, s
->_socket
);
2371 if (callout
) callout(s
, kCFSocketAcceptCallBack
, address
, &sock
, contextInfo
);
2374 } else if (kCFSocketReadCallBack
== readCallBackType
) {
2375 if (readSignalled
&& (!calledOut
|| CFSocketIsValid(s
))) {
2376 #if defined(LOG_CFSOCKET)
2377 fprintf(stdout
, "perform calling out read to socket %d\n", s
->_socket
);
2379 // CFLog(5, CFSTR("__CFSocketPerformV0(%p) doing read callback"), s);
2380 if (callout
) callout(s
, kCFSocketReadCallBack
, NULL
, NULL
, contextInfo
);
2384 if ((callBackTypes
& kCFSocketWriteCallBack
) != 0) {
2385 if (writeSignalled
&& !errorCode
&& (!calledOut
|| CFSocketIsValid(s
))) {
2386 #if defined(LOG_CFSOCKET)
2387 fprintf(stdout
, "perform calling out write to socket %d\n", s
->_socket
);
2389 // CFLog(5, CFSTR("__CFSocketPerformV0(%p) doing write callback"), s);
2390 if (callout
) callout(s
, kCFSocketWriteCallBack
, NULL
, NULL
, contextInfo
);
2396 static void __CFSocketPerformV0(void *info
) {
2397 CFSocketRef s
= info
;
2398 CFDataRef data
= NULL
;
2399 CFDataRef address
= NULL
;
2400 CFSocketNativeHandle sock
= INVALID_SOCKET
;
2401 uint8_t readCallBackType
, callBackTypes
;
2402 CFRunLoopRef rl
= NULL
;
2403 // CFLog(5, CFSTR("__CFSocketPerformV0(%p) starting"), s);
2406 if (!__CFSocketIsValid(s
)) {
2407 __CFSocketUnlock(s
);
2410 callBackTypes
= __CFSocketCallBackTypes(s
);
2411 readCallBackType
= __CFSocketReadCallBackType(s
);
2412 CFOptionFlags callBacksSignalled
= 0;
2413 if (__CFSocketIsReadSignalled(s
)) callBacksSignalled
|= readCallBackType
;
2414 if (__CFSocketIsWriteSignalled(s
)) callBacksSignalled
|= kCFSocketWriteCallBack
;
2416 if (kCFSocketDataCallBack
== readCallBackType
) {
2417 if (NULL
!= s
->_dataQueue
&& 0 < CFArrayGetCount(s
->_dataQueue
)) {
2418 data
= CFArrayGetValueAtIndex(s
->_dataQueue
, 0);
2420 CFArrayRemoveValueAtIndex(s
->_dataQueue
, 0);
2421 address
= CFArrayGetValueAtIndex(s
->_addressQueue
, 0);
2423 CFArrayRemoveValueAtIndex(s
->_addressQueue
, 0);
2425 } else if (kCFSocketAcceptCallBack
== readCallBackType
) {
2426 if (NULL
!= s
->_dataQueue
&& 0 < CFArrayGetCount(s
->_dataQueue
)) {
2427 sock
= (CFSocketNativeHandle
)(uintptr_t)CFArrayGetValueAtIndex(s
->_dataQueue
, 0);
2428 CFArrayRemoveValueAtIndex(s
->_dataQueue
, 0);
2429 address
= CFArrayGetValueAtIndex(s
->_addressQueue
, 0);
2431 CFArrayRemoveValueAtIndex(s
->_addressQueue
, 0);
2435 __CFSocketDoCallback(s
, data
, address
, sock
); // does __CFSocketUnlock(s)
2436 if (NULL
!= data
) CFRelease(data
);
2437 if (NULL
!= address
) CFRelease(address
);
2440 if (__CFSocketIsValid(s
) && kCFSocketNoCallBack
!= readCallBackType
) {
2441 // if there's still more data, we want to wake back up right away
2442 if ((kCFSocketDataCallBack
== readCallBackType
|| kCFSocketAcceptCallBack
== readCallBackType
) && NULL
!= s
->_dataQueue
&& 0 < CFArrayGetCount(s
->_dataQueue
)) {
2443 CFRunLoopSourceSignal(s
->_source0
);
2444 #if defined(LOG_CFSOCKET)
2445 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
);
2447 rl
= __CFSocketCopyRunLoopToWakeUp(s
);
2450 // Only reenable callbacks that are auto-reenabled
2451 __CFSocketEnableCallBacks(s
, callBacksSignalled
& s
->_f
.client
, FALSE
, 'p'); // unlocks s
2454 CFRunLoopWakeUp(rl
);
2457 // CFLog(5, CFSTR("__CFSocketPerformV0(%p) done"), s);
2460 CFRunLoopSourceRef
CFSocketCreateRunLoopSource(CFAllocatorRef allocator
, CFSocketRef s
, CFIndex order
) {
2462 CFRunLoopSourceRef result
= NULL
;
2463 __CFGenericValidateType(s
, CFSocketGetTypeID());
2465 if (__CFSocketIsValid(s
)) {
2466 if (NULL
== s
->_source0
) {
2467 CFRunLoopSourceContext context
;
2468 context
.version
= 0;
2470 context
.retain
= CFRetain
;
2471 context
.release
= CFRelease
;
2472 context
.copyDescription
= CFCopyDescription
;
2473 context
.equal
= CFEqual
;
2474 context
.hash
= CFHash
;
2475 context
.schedule
= __CFSocketSchedule
;
2476 context
.cancel
= __CFSocketCancel
;
2477 context
.perform
= __CFSocketPerformV0
;
2478 s
->_source0
= CFRunLoopSourceCreate(allocator
, order
, &context
);
2480 CFRetain(s
->_source0
); /* This retain is for the receiver */
2481 result
= s
->_source0
;
2483 __CFSocketUnlock(s
);
2487 #endif /* NEW_SOCKET */
2491 static uint16_t __CFSocketDefaultNameRegistryPortNumber
= 2454;
2493 CONST_STRING_DECL(kCFSocketCommandKey
, "Command")
2494 CONST_STRING_DECL(kCFSocketNameKey
, "Name")
2495 CONST_STRING_DECL(kCFSocketValueKey
, "Value")
2496 CONST_STRING_DECL(kCFSocketResultKey
, "Result")
2497 CONST_STRING_DECL(kCFSocketErrorKey
, "Error")
2498 CONST_STRING_DECL(kCFSocketRegisterCommand
, "Register")
2499 CONST_STRING_DECL(kCFSocketRetrieveCommand
, "Retrieve")
2500 CONST_STRING_DECL(__kCFSocketRegistryRequestRunLoopMode
, "CFSocketRegistryRequest")
2502 static CFSpinLock_t __CFSocketWriteLock_
= CFSpinLockInit
;
2503 //#warning can only send on one socket at a time now
2505 CF_INLINE
void __CFSocketWriteLock(CFSocketRef s
) {
2506 __CFSpinLock(& __CFSocketWriteLock_
);
2509 CF_INLINE
void __CFSocketWriteUnlock(CFSocketRef s
) {
2510 __CFSpinUnlock(& __CFSocketWriteLock_
);
2515 CF_INLINE CFIndex
__CFSocketFdGetSize(CFDataRef fdSet
) {
2516 return NBBY
* CFDataGetLength(fdSet
);
2519 CF_INLINE Boolean
__CFSocketFdSet(CFSocketNativeHandle sock
, CFMutableDataRef fdSet
) {
2520 /* returns true if a change occurred, false otherwise */
2521 Boolean retval
= false;
2522 if (INVALID_SOCKET
!= sock
&& 0 <= sock
) {
2523 CFIndex numFds
= NBBY
* CFDataGetLength(fdSet
);
2525 if (sock
>= numFds
) {
2526 CFIndex oldSize
= numFds
/ NFDBITS
, newSize
= (sock
+ NFDBITS
) / NFDBITS
, changeInBytes
= (newSize
- oldSize
) * sizeof(fd_mask
);
2527 CFDataIncreaseLength(fdSet
, changeInBytes
);
2528 fds_bits
= (fd_mask
*)CFDataGetMutableBytePtr(fdSet
);
2529 memset(fds_bits
+ oldSize
, 0, changeInBytes
);
2531 fds_bits
= (fd_mask
*)CFDataGetMutableBytePtr(fdSet
);
2533 if (!FD_ISSET(sock
, (fd_set
*)fds_bits
)) {
2535 FD_SET(sock
, (fd_set
*)fds_bits
);
2543 //??? need timeout, error handling, retries
2544 CFSocketError
CFSocketSendData(CFSocketRef s
, CFDataRef address
, CFDataRef data
, CFTimeInterval timeout
) {
2546 const uint8_t *dataptr
, *addrptr
= NULL
;
2547 SInt32 datalen
, addrlen
= 0, size
= 0;
2548 CFSocketNativeHandle sock
= INVALID_SOCKET
;
2550 __CFGenericValidateType(s
, CFSocketGetTypeID());
2552 addrptr
= CFDataGetBytePtr(address
);
2553 addrlen
= CFDataGetLength(address
);
2555 dataptr
= CFDataGetBytePtr(data
);
2556 datalen
= CFDataGetLength(data
);
2557 if (CFSocketIsValid(s
)) sock
= CFSocketGetNative(s
);
2558 if (INVALID_SOCKET
!= sock
) {
2560 __CFSocketWriteLock(s
);
2561 tv
.tv_sec
= (timeout
<= 0.0 || (CFTimeInterval
)INT_MAX
<= timeout
) ? INT_MAX
: (int)floor(timeout
);
2562 tv
.tv_usec
= (int)floor(1.0e+6 * (timeout
- floor(timeout
)));
2563 setsockopt(sock
, SOL_SOCKET
, SO_SNDTIMEO
, (void *)&tv
, sizeof(tv
)); // cast for WinSock bad API
2564 if (NULL
!= addrptr
&& 0 < addrlen
) {
2565 size
= sendto(sock
, dataptr
, datalen
, 0, (struct sockaddr
*)addrptr
, addrlen
);
2567 size
= send(sock
, dataptr
, datalen
, 0);
2569 #if defined(LOG_CFSOCKET)
2570 fprintf(stdout
, "wrote %ld bytes to socket %d\n", size
, sock
);
2572 __CFSocketWriteUnlock(s
);
2575 return (size
> 0) ? kCFSocketSuccess
: kCFSocketError
;
2578 CFSocketError
CFSocketSetAddress(CFSocketRef s
, CFDataRef address
) {
2580 const uint8_t *name
;
2581 SInt32 namelen
, result
= 0;
2582 __CFGenericValidateType(s
, CFSocketGetTypeID());
2583 if (NULL
== address
) return -1;
2584 if (!CFSocketIsValid(s
)) return 0;
2585 name
= CFDataGetBytePtr(address
);
2586 namelen
= CFDataGetLength(address
);
2587 if (!name
|| namelen
<= 0) return 0;
2588 CFSocketNativeHandle sock
= CFSocketGetNative(s
);
2589 result
= bind(sock
, (struct sockaddr
*)name
, namelen
);
2593 //??? should return errno
2597 CFSocketError
CFSocketConnectToAddress(CFSocketRef s
, CFDataRef address
, CFTimeInterval timeout
) {
2599 //??? need error handling, retries
2600 const uint8_t *name
;
2601 SInt32 namelen
, result
= -1, connect_err
= 0, select_err
= 0;
2602 UInt32 yes
= 1, no
= 0;
2603 Boolean wasBlocking
= true;
2605 __CFGenericValidateType(s
, CFSocketGetTypeID());
2606 if (!CFSocketIsValid(s
)) return 0;
2607 name
= CFDataGetBytePtr(address
);
2608 namelen
= CFDataGetLength(address
);
2609 if (!name
|| namelen
<= 0) return 0;
2610 CFSocketNativeHandle sock
= CFSocketGetNative(s
);
2612 SInt32 flags
= fcntl(sock
, F_GETFL
, 0);
2613 if (flags
>= 0) wasBlocking
= ((flags
& O_NONBLOCK
) == 0);
2614 if (wasBlocking
&& (timeout
> 0.0 || timeout
< 0.0)) ioctl(sock
, FIONBIO
, &yes
);
2615 result
= connect(sock
, (struct sockaddr
*)name
, namelen
);
2617 connect_err
= thread_errno();
2619 #if defined(LOG_CFSOCKET)
2620 fprintf(stdout
, "connection attempt returns %ld error %ld on socket %d (flags 0x%lx blocking %d)\n", result
, connect_err
, sock
, flags
, wasBlocking
);
2622 if (EINPROGRESS
== connect_err
&& timeout
>= 0.0) {
2623 /* select on socket */
2625 int error_size
= sizeof(select_err
);
2627 CFMutableDataRef fds
= CFDataCreateMutable(kCFAllocatorSystemDefault
, 0);
2628 __CFSocketFdSet(sock
, fds
);
2629 tv
.tv_sec
= (timeout
<= 0.0 || (CFTimeInterval
)INT_MAX
<= timeout
) ? INT_MAX
: (int)floor(timeout
);
2630 tv
.tv_usec
= (int)floor(1.0e+6 * (timeout
- floor(timeout
)));
2631 nrfds
= select(__CFSocketFdGetSize(fds
), NULL
, (fd_set
*)CFDataGetMutableBytePtr(fds
), NULL
, &tv
);
2633 select_err
= thread_errno();
2635 } else if (nrfds
== 0) {
2638 if (0 != getsockopt(sock
, SOL_SOCKET
, SO_ERROR
, (void *)&select_err
, (socklen_t
*)&error_size
)) select_err
= 0;
2639 result
= (select_err
== 0) ? 0 : -1;
2642 #if defined(LOG_CFSOCKET)
2643 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
);
2646 if (wasBlocking
&& (timeout
> 0.0 || timeout
< 0.0)) ioctl(sock
, FIONBIO
, &no
);
2647 if (EINPROGRESS
== connect_err
&& timeout
< 0.0) {
2649 #if defined(LOG_CFSOCKET)
2650 fprintf(stdout
, "connection attempt continues in background on socket %d\n", sock
);
2654 //??? should return errno
2658 CFSocketRef
CFSocketCreate(CFAllocatorRef allocator
, SInt32 protocolFamily
, SInt32 socketType
, SInt32 protocol
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
) {
2660 CFSocketNativeHandle sock
= INVALID_SOCKET
;
2661 CFSocketRef s
= NULL
;
2662 if (0 >= protocolFamily
) protocolFamily
= PF_INET
;
2663 if (PF_INET
== protocolFamily
) {
2664 if (0 >= socketType
) socketType
= SOCK_STREAM
;
2665 if (0 >= protocol
&& SOCK_STREAM
== socketType
) protocol
= IPPROTO_TCP
;
2666 if (0 >= protocol
&& SOCK_DGRAM
== socketType
) protocol
= IPPROTO_UDP
;
2668 if (PF_LOCAL
== protocolFamily
&& 0 >= socketType
) socketType
= SOCK_STREAM
;
2669 sock
= socket(protocolFamily
, socketType
, protocol
);
2670 if (INVALID_SOCKET
!= sock
) {
2671 s
= CFSocketCreateWithNative(allocator
, sock
, callBackTypes
, callout
, context
);
2676 CFSocketRef
CFSocketCreateWithSocketSignature(CFAllocatorRef allocator
, const CFSocketSignature
*signature
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
) {
2678 CFSocketRef s
= CFSocketCreate(allocator
, signature
->protocolFamily
, signature
->socketType
, signature
->protocol
, callBackTypes
, callout
, context
);
2679 if (NULL
!= s
&& (!CFSocketIsValid(s
) || kCFSocketSuccess
!= CFSocketSetAddress(s
, signature
->address
))) {
2680 CFSocketInvalidate(s
);
2687 CFSocketRef
CFSocketCreateConnectedToSocketSignature(CFAllocatorRef allocator
, const CFSocketSignature
*signature
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
, CFTimeInterval timeout
) {
2689 CFSocketRef s
= CFSocketCreate(allocator
, signature
->protocolFamily
, signature
->socketType
, signature
->protocol
, callBackTypes
, callout
, context
);
2690 if (NULL
!= s
&& (!CFSocketIsValid(s
) || kCFSocketSuccess
!= CFSocketConnectToAddress(s
, signature
->address
, timeout
))) {
2691 CFSocketInvalidate(s
);
2699 CFSocketError
*error
;
2700 CFPropertyListRef
*value
;
2702 } __CFSocketNameRegistryResponse
;
2704 static void __CFSocketHandleNameRegistryReply(CFSocketRef s
, CFSocketCallBackType type
, CFDataRef address
, const void *data
, void *info
) {
2705 CFDataRef replyData
= (CFDataRef
)data
;
2706 __CFSocketNameRegistryResponse
*response
= (__CFSocketNameRegistryResponse
*)info
;
2707 CFDictionaryRef replyDictionary
= NULL
;
2708 CFPropertyListRef value
;
2709 replyDictionary
= CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault
, replyData
, kCFPropertyListImmutable
, NULL
);
2710 if (NULL
!= response
->error
) *(response
->error
) = kCFSocketError
;
2711 if (NULL
!= replyDictionary
) {
2712 if (CFGetTypeID((CFTypeRef
)replyDictionary
) == CFDictionaryGetTypeID() && NULL
!= (value
= CFDictionaryGetValue(replyDictionary
, kCFSocketResultKey
))) {
2713 if (NULL
!= response
->error
) *(response
->error
) = kCFSocketSuccess
;
2714 if (NULL
!= response
->value
) *(response
->value
) = CFRetain(value
);
2715 if (NULL
!= response
->address
) *(response
->address
) = address
? CFDataCreateCopy(kCFAllocatorSystemDefault
, address
) : NULL
;
2717 CFRelease(replyDictionary
);
2719 CFSocketInvalidate(s
);
2722 static void __CFSocketSendNameRegistryRequest(CFSocketSignature
*signature
, CFDictionaryRef requestDictionary
, __CFSocketNameRegistryResponse
*response
, CFTimeInterval timeout
) {
2723 CFDataRef requestData
= NULL
;
2724 CFSocketContext context
= {0, response
, NULL
, NULL
, NULL
};
2725 CFSocketRef s
= NULL
;
2726 CFRunLoopSourceRef source
= NULL
;
2727 if (NULL
!= response
->error
) *(response
->error
) = kCFSocketError
;
2728 requestData
= CFPropertyListCreateXMLData(kCFAllocatorSystemDefault
, requestDictionary
);
2729 if (NULL
!= requestData
) {
2730 if (NULL
!= response
->error
) *(response
->error
) = kCFSocketTimeout
;
2731 s
= CFSocketCreateConnectedToSocketSignature(kCFAllocatorSystemDefault
, signature
, kCFSocketDataCallBack
, __CFSocketHandleNameRegistryReply
, &context
, timeout
);
2733 if (kCFSocketSuccess
== CFSocketSendData(s
, NULL
, requestData
, timeout
)) {
2734 source
= CFSocketCreateRunLoopSource(kCFAllocatorSystemDefault
, s
, 0);
2735 CFRunLoopAddSource(CFRunLoopGetCurrent(), source
, __kCFSocketRegistryRequestRunLoopMode
);
2736 CFRunLoopRunInMode(__kCFSocketRegistryRequestRunLoopMode
, timeout
, false);
2739 CFSocketInvalidate(s
);
2742 CFRelease(requestData
);
2746 static void __CFSocketValidateSignature(const CFSocketSignature
*providedSignature
, CFSocketSignature
*signature
, uint16_t defaultPortNumber
) {
2747 struct sockaddr_in sain
, *sainp
;
2748 memset(&sain
, 0, sizeof(sain
));
2749 sain
.sin_len
= sizeof(sain
);
2750 sain
.sin_family
= AF_INET
;
2751 sain
.sin_port
= htons(__CFSocketDefaultNameRegistryPortNumber
);
2752 sain
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
2753 if (NULL
== providedSignature
) {
2754 signature
->protocolFamily
= PF_INET
;
2755 signature
->socketType
= SOCK_STREAM
;
2756 signature
->protocol
= IPPROTO_TCP
;
2757 signature
->address
= CFDataCreate(kCFAllocatorSystemDefault
, (uint8_t *)&sain
, sizeof(sain
));
2759 signature
->protocolFamily
= providedSignature
->protocolFamily
;
2760 signature
->socketType
= providedSignature
->socketType
;
2761 signature
->protocol
= providedSignature
->protocol
;
2762 if (0 >= signature
->protocolFamily
) signature
->protocolFamily
= PF_INET
;
2763 if (PF_INET
== signature
->protocolFamily
) {
2764 if (0 >= signature
->socketType
) signature
->socketType
= SOCK_STREAM
;
2765 if (0 >= signature
->protocol
&& SOCK_STREAM
== signature
->socketType
) signature
->protocol
= IPPROTO_TCP
;
2766 if (0 >= signature
->protocol
&& SOCK_DGRAM
== signature
->socketType
) signature
->protocol
= IPPROTO_UDP
;
2768 if (NULL
== providedSignature
->address
) {
2769 signature
->address
= CFDataCreate(kCFAllocatorSystemDefault
, (uint8_t *)&sain
, sizeof(sain
));
2771 sainp
= (struct sockaddr_in
*)CFDataGetBytePtr(providedSignature
->address
);
2772 if ((int)sizeof(struct sockaddr_in
) <= CFDataGetLength(providedSignature
->address
) && (AF_INET
== sainp
->sin_family
|| 0 == sainp
->sin_family
)) {
2773 sain
.sin_len
= sizeof(sain
);
2774 sain
.sin_family
= AF_INET
;
2775 sain
.sin_port
= sainp
->sin_port
;
2776 if (0 == sain
.sin_port
) sain
.sin_port
= htons(defaultPortNumber
);
2777 sain
.sin_addr
.s_addr
= sainp
->sin_addr
.s_addr
;
2778 if (htonl(INADDR_ANY
) == sain
.sin_addr
.s_addr
) sain
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
2779 signature
->address
= CFDataCreate(kCFAllocatorSystemDefault
, (uint8_t *)&sain
, sizeof(sain
));
2781 signature
->address
= CFRetain(providedSignature
->address
);
2787 CFSocketError
CFSocketRegisterValue(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
, CFPropertyListRef value
) {
2788 CFSocketSignature signature
;
2789 CFMutableDictionaryRef dictionary
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 3, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2790 CFSocketError retval
= kCFSocketError
;
2791 __CFSocketNameRegistryResponse response
= {&retval
, NULL
, NULL
};
2792 CFDictionaryAddValue(dictionary
, kCFSocketCommandKey
, kCFSocketRegisterCommand
);
2793 CFDictionaryAddValue(dictionary
, kCFSocketNameKey
, name
);
2794 if (NULL
!= value
) CFDictionaryAddValue(dictionary
, kCFSocketValueKey
, value
);
2795 __CFSocketValidateSignature(nameServerSignature
, &signature
, __CFSocketDefaultNameRegistryPortNumber
);
2796 __CFSocketSendNameRegistryRequest(&signature
, dictionary
, &response
, timeout
);
2797 CFRelease(dictionary
);
2798 CFRelease(signature
.address
);
2802 CFSocketError
CFSocketCopyRegisteredValue(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
, CFPropertyListRef
*value
, CFDataRef
*serverAddress
) {
2803 CFSocketSignature signature
;
2804 CFMutableDictionaryRef dictionary
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 2, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2805 CFSocketError retval
= kCFSocketError
;
2806 __CFSocketNameRegistryResponse response
= {&retval
, value
, serverAddress
};
2807 CFDictionaryAddValue(dictionary
, kCFSocketCommandKey
, kCFSocketRetrieveCommand
);
2808 CFDictionaryAddValue(dictionary
, kCFSocketNameKey
, name
);
2809 __CFSocketValidateSignature(nameServerSignature
, &signature
, __CFSocketDefaultNameRegistryPortNumber
);
2810 __CFSocketSendNameRegistryRequest(&signature
, dictionary
, &response
, timeout
);
2811 CFRelease(dictionary
);
2812 CFRelease(signature
.address
);
2816 CFSocketError
CFSocketRegisterSocketSignature(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
, const CFSocketSignature
*signature
) {
2817 CFSocketSignature validatedSignature
;
2818 CFMutableDataRef data
= NULL
;
2819 CFSocketError retval
;
2822 if (NULL
== signature
) {
2823 retval
= CFSocketUnregister(nameServerSignature
, timeout
, name
);
2825 __CFSocketValidateSignature(signature
, &validatedSignature
, 0);
2826 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
) {
2827 retval
= kCFSocketError
;
2829 data
= CFDataCreateMutable(kCFAllocatorSystemDefault
, sizeof(bytes
) + length
);
2830 bytes
[0] = validatedSignature
.protocolFamily
;
2831 bytes
[1] = validatedSignature
.socketType
;
2832 bytes
[2] = validatedSignature
.protocol
;
2834 CFDataAppendBytes(data
, bytes
, sizeof(bytes
));
2835 CFDataAppendBytes(data
, CFDataGetBytePtr(validatedSignature
.address
), length
);
2836 retval
= CFSocketRegisterValue(nameServerSignature
, timeout
, name
, data
);
2839 CFRelease(validatedSignature
.address
);
2844 CFSocketError
CFSocketCopyRegisteredSocketSignature(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
, CFSocketSignature
*signature
, CFDataRef
*nameServerAddress
) {
2845 CFDataRef data
= NULL
;
2846 CFSocketSignature returnedSignature
;
2847 const uint8_t *ptr
= NULL
, *aptr
= NULL
;
2850 CFDataRef serverAddress
= NULL
;
2851 CFSocketError retval
= CFSocketCopyRegisteredValue(nameServerSignature
, timeout
, name
, (CFPropertyListRef
*)&data
, &serverAddress
);
2852 if (NULL
== data
|| CFGetTypeID(data
) != CFDataGetTypeID() || NULL
== (ptr
= CFDataGetBytePtr(data
)) || (length
= CFDataGetLength(data
)) < 4) retval
= kCFSocketError
;
2853 if (kCFSocketSuccess
== retval
&& NULL
!= signature
) {
2854 returnedSignature
.protocolFamily
= (SInt32
)*ptr
++;
2855 returnedSignature
.socketType
= (SInt32
)*ptr
++;
2856 returnedSignature
.protocol
= (SInt32
)*ptr
++;
2858 returnedSignature
.address
= CFDataCreate(kCFAllocatorSystemDefault
, ptr
, length
- 4);
2859 __CFSocketValidateSignature(&returnedSignature
, signature
, 0);
2860 CFRelease(returnedSignature
.address
);
2861 ptr
= CFDataGetBytePtr(signature
->address
);
2862 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
) {
2863 CFMutableDataRef address
= CFDataCreateMutableCopy(kCFAllocatorSystemDefault
, CFDataGetLength(signature
->address
), signature
->address
);
2864 mptr
= CFDataGetMutableBytePtr(address
);
2865 ((struct sockaddr_in
*)mptr
)->sin_addr
= ((struct sockaddr_in
*)aptr
)->sin_addr
;
2866 CFRelease(signature
->address
);
2867 signature
->address
= address
;
2869 if (NULL
!= nameServerAddress
) *nameServerAddress
= serverAddress
? CFRetain(serverAddress
) : NULL
;
2871 if (NULL
!= data
) CFRelease(data
);
2872 if (NULL
!= serverAddress
) CFRelease(serverAddress
);
2876 CFSocketError
CFSocketUnregister(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
) {
2877 return CFSocketRegisterValue(nameServerSignature
, timeout
, name
, NULL
);
2880 CF_EXPORT
void CFSocketSetDefaultNameRegistryPortNumber(uint16_t port
) {
2881 __CFSocketDefaultNameRegistryPortNumber
= port
;
2884 CF_EXPORT
uint16_t CFSocketGetDefaultNameRegistryPortNumber(void) {
2885 return __CFSocketDefaultNameRegistryPortNumber
;