2 * Copyright (c) 2014 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-2013, 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 <dispatch/private.h>
38 #include <netinet/in.h>
39 #include <sys/sysctl.h>
40 #include <sys/socket.h>
41 #include <sys/ioctl.h>
45 #include <sys/select.h>
48 extern void _CFRunLoopSourceWakeUpRunLoops(CFRunLoopSourceRef rls);
50 #define INVALID_SOCKET (CFSocketNativeHandle)(-1)
51 #define MAX_SOCKADDR_LEN 256
54 DISPATCH_HELPER_FUNCTIONS(sock, CFSocket)
56 static Boolean sockfd_is_readable(int fd) {
57 if (fd < 0 || 1048576 <= fd) HALT;
58 size_t sz = ((fd + CHAR_BIT) / CHAR_BIT) + 7; // generous
59 fd_set *fdset = malloc(sz);
64 struct timespec ts = {0, 1000UL}; // 1 us
65 ret = pselect(fd + 1, fdset, NULL, NULL, &ts, NULL);
66 } while (ret < 0 && (EINTR == errno || EAGAIN == errno));
67 Boolean isSet = ((0 < ret) && FD_ISSET(fd, fdset));
72 static Boolean sockfd_is_writeable(int fd) {
73 if (fd < 0 || 1048576 <= fd) HALT;
74 size_t sz = ((fd + CHAR_BIT) / CHAR_BIT) + 7; // generous
75 fd_set *fdset = malloc(sz);
80 struct timespec ts = {0, 1000UL}; // 1 us
81 ret = pselect(fd + 1, NULL, fdset, NULL, &ts, NULL);
82 } while (ret < 0 && (EINTR == errno || EAGAIN == errno));
83 Boolean isSet = ((0 < ret) && FD_ISSET(fd, fdset));
90 kCFSocketStateReady = 0,
91 kCFSocketStateInvalidating = 1,
92 kCFSocketStateInvalid = 2,
93 kCFSocketStateDeallocating = 3
96 struct __shared_blob {
97 dispatch_source_t _rdsrc;
98 dispatch_source_t _wrsrc;
99 CFRunLoopSourceRef _source;
100 CFSocketNativeHandle _socket;
107 struct __shared_blob *_shared; // non-NULL when valid, NULL when invalid
109 uint8_t _state:2; // mutable, not written safely
110 uint8_t _isSaneFD:1; // immutable
111 uint8_t _connOriented:1; // immutable
112 uint8_t _wantConnect:1; // immutable
113 uint8_t _wantWrite:1; // immutable
114 uint8_t _wantReadType:2; // immutable
118 uint8_t _rsuspended:1;
119 uint8_t _wsuspended:1;
121 uint8_t _writeable:1;
124 uint8_t _reenableRead:1;
125 uint8_t _readDisabled:1;
126 uint8_t _reenableWrite:1;
127 uint8_t _writeDisabled:1;
128 uint8_t _connectDisabled:1;
129 uint8_t _connected:1;
130 uint8_t _leaveErrors:1;
131 uint8_t _closeOnInvalidate:1;
133 int32_t _runLoopCounter;
135 CFDataRef _address; // immutable, once created
136 CFDataRef _peerAddress; // immutable, once created
137 CFSocketCallBack _callout; // immutable
138 CFSocketContext _context; // immutable
142 CF_INLINE Boolean __CFSocketIsValid(CFSocketRef sock) {
143 return kCFSocketStateReady == sock->_state;
146 static CFStringRef __CFSocketCopyDescription(CFTypeRef cf) {
147 CFSocketRef sock = (CFSocketRef)cf;
148 CFStringRef contextDesc = NULL;
149 if (NULL != sock->_context.info && NULL != sock->_context.copyDescription) {
150 contextDesc = sock->_context.copyDescription(sock->_context.info);
152 if (NULL == contextDesc) {
153 contextDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFSocket context %p>"), sock->_context.info);
156 void *addr = sock->_callout;
157 const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???";
159 ioctlsocket(sock->_shared ? sock->_shared->_socket : -1, FIONREAD, &avail);
160 CFStringRef result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR(
161 "<CFSocket %p [%p]>{valid = %s, socket = %d, "
162 "want connect = %s, connect disabled = %s, "
163 "want write = %s, reenable write = %s, write disabled = %s, "
164 "want read = %s, reenable read = %s, read disabled = %s, "
165 "leave errors = %s, close on invalidate = %s, connected = %s, "
166 "last error code = %d, bytes available for read = %d, "
167 "source = %p, callout = %s (%p), context = %@}"),
168 cf, CFGetAllocator(sock), __CFSocketIsValid(sock) ? "Yes" : "No", sock->_shared ? sock->_shared->_socket : -1,
169 sock->_wantConnect ? "Yes" : "No", sock->_connectDisabled ? "Yes" : "No",
170 sock->_wantWrite ? "Yes" : "No", sock->_reenableWrite ? "Yes" : "No", sock->_writeDisabled ? "Yes" : "No",
171 sock->_wantReadType ? "Yes" : "No", sock->_reenableRead ? "Yes" : "No", sock->_readDisabled? "Yes" : "No",
172 sock->_leaveErrors ? "Yes" : "No", sock->_closeOnInvalidate ? "Yes" : "No", sock->_connected ? "Yes" : "No",
174 sock->_shared ? sock->_shared->_source : NULL, name, addr, contextDesc);
175 if (NULL != contextDesc) {
176 CFRelease(contextDesc);
181 static void __CFSocketDeallocate(CFTypeRef cf) {
182 CHECK_FOR_FORK_RET();
183 CFSocketRef sock = (CFSocketRef)cf;
184 // Since CFSockets are cached, we can only get here sometime after being invalidated
185 sock->_state = kCFSocketStateDeallocating;
186 if (sock->_peerAddress) {
187 CFRelease(sock->_peerAddress);
188 sock->_peerAddress = NULL;
190 if (sock->_address) {
191 CFRelease(sock->_address);
192 sock->_address = NULL;
196 static CFTypeID __kCFSocketTypeID = _kCFRuntimeNotATypeID;
198 static const CFRuntimeClass __CFSocketClass = {
203 __CFSocketDeallocate,
207 __CFSocketCopyDescription
210 static CFMutableArrayRef __CFAllSockets = NULL;
212 CFTypeID CFSocketGetTypeID(void) {
213 if (_kCFRuntimeNotATypeID == __kCFSocketTypeID) {
214 __kCFSocketTypeID = _CFRuntimeRegisterClass(&__CFSocketClass);
215 __CFAllSockets = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
217 int ret1 = getrlimit(RLIMIT_NOFILE, &lim1);
218 int mib[] = {CTL_KERN, KERN_MAXFILESPERPROC};
220 size_t len = sizeof(int);
221 int ret0 = sysctl(mib, 2, &maxfd, &len, NULL, 0);
222 if (0 == ret0 && 0 == ret1 && lim1.rlim_max < maxfd) maxfd = lim1.rlim_max;
223 if (0 == ret1 && lim1.rlim_cur < maxfd) {
224 struct rlimit lim2 = lim1;
225 lim2.rlim_cur += 2304;
226 if (maxfd < lim2.rlim_cur) lim2.rlim_cur = maxfd;
227 setrlimit(RLIMIT_NOFILE, &lim2);
228 // we try, but do not go to extraordinary measures
231 return __kCFSocketTypeID;
234 CFSocketRef CFSocketCreateWithNative(CFAllocatorRef allocator, CFSocketNativeHandle ufd, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context) {
235 CHECK_FOR_FORK_RET(NULL);
237 CFSocketGetTypeID(); // cause initialization if necessary
240 int ret = fstat(ufd, &statbuf);
241 if (ret < 0) ufd = INVALID_SOCKET;
243 Boolean sane = false;
244 if (INVALID_SOCKET != ufd) {
245 uint32_t type = (statbuf.st_mode & S_IFMT);
246 sane = (S_IFSOCK == type) || (S_IFIFO == type) || (S_IFCHR == type);
248 CFLog(kCFLogLevelWarning, CFSTR("*** CFSocketCreateWithNative(): creating CFSocket with silly fd type (%07o) -- may or may not work"), type);
252 if (INVALID_SOCKET != ufd) {
253 Boolean canHandle = false;
254 int tmp_kq = kqueue();
257 EV_SET(&ev[0], ufd, EVFILT_READ, EV_ADD, 0, 0, 0);
258 EV_SET(&ev[1], ufd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
259 int ret = kevent(tmp_kq, ev, 2, NULL, 0, NULL);
260 canHandle = (0 <= ret); // if kevent(ADD) succeeds, can handle
263 if (1 && !canHandle) {
264 CFLog(kCFLogLevelWarning, CFSTR("*** CFSocketCreateWithNative(): creating CFSocket with unsupported fd type -- may or may not work"));
268 if (INVALID_SOCKET == ufd) {
269 // Historically, bad ufd was allowed, but gave an uncached and already-invalid CFSocketRef
270 SInt32 size = sizeof(struct __CFSocket) - sizeof(CFRuntimeBase);
271 CFSocketRef memory = (CFSocketRef)_CFRuntimeCreateInstance(allocator, CFSocketGetTypeID(), size, NULL);
272 if (NULL == memory) {
275 memory->_callout = callout;
276 memory->_state = kCFSocketStateInvalid;
280 __block CFSocketRef sock = NULL;
281 dispatch_sync(__sockQueue(), ^{
282 for (CFIndex idx = 0, cnt = CFArrayGetCount(__CFAllSockets); idx < cnt; idx++) {
283 CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(__CFAllSockets, idx);
284 if (s->_shared->_socket == ufd) {
291 SInt32 size = sizeof(struct __CFSocket) - sizeof(CFRuntimeBase);
292 CFSocketRef memory = (CFSocketRef)_CFRuntimeCreateInstance(allocator, CFSocketGetTypeID(), size, NULL);
293 if (NULL == memory) {
298 if (INVALID_SOCKET != ufd) {
299 socklen_t typeSize = sizeof(socketType);
300 int ret = getsockopt(ufd, SOL_SOCKET, SO_TYPE, (void *)&socketType, (socklen_t *)&typeSize);
301 if (ret < 0) socketType = 0;
304 memory->_rsuspended = true;
305 memory->_wsuspended = true;
306 memory->_readable = false;
307 memory->_writeable = false;
309 memory->_isSaneFD = sane ? 1 : 0;
310 memory->_wantReadType = (callBackTypes & 0x3);
311 memory->_reenableRead = memory->_wantReadType ? true : false;
312 memory->_readDisabled = false;
313 memory->_wantWrite = (callBackTypes & kCFSocketWriteCallBack) ? true : false;
314 memory->_reenableWrite = false;
315 memory->_writeDisabled = false;
316 memory->_wantConnect = (callBackTypes & kCFSocketConnectCallBack) ? true : false;
317 memory->_connectDisabled = false;
318 memory->_leaveErrors = false;
319 memory->_closeOnInvalidate = true;
320 memory->_connOriented = (SOCK_STREAM == socketType || SOCK_SEQPACKET == socketType);
321 memory->_connected = (memory->_wantReadType == kCFSocketAcceptCallBack || !memory->_connOriented) ? true : false;
324 memory->_runLoopCounter = 0;
325 memory->_address = NULL;
326 memory->_peerAddress = NULL;
327 memory->_context.info = NULL;
328 memory->_context.retain = NULL;
329 memory->_context.release = NULL;
330 memory->_context.copyDescription = NULL;
331 memory->_callout = callout;
332 if (NULL != context) {
333 objc_memmove_collectable(&memory->_context, context, sizeof(CFSocketContext));
334 memory->_context.info = context->retain ? (void *)context->retain(context->info) : context->info;
337 struct __shared_blob *shared = malloc(sizeof(struct __shared_blob));
338 shared->_rdsrc = NULL;
339 shared->_wrsrc = NULL;
340 shared->_source = NULL;
341 shared->_socket = ufd;
342 shared->_closeFD = true; // copy of _closeOnInvalidate
343 shared->_refCnt = 1; // one for the CFSocket
344 memory->_shared = shared;
346 if (memory->_wantReadType) {
347 dispatch_source_t dsrc = NULL;
349 dsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, ufd, 0, __sockQueue());
351 dsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, __sockQueue());
352 dispatch_source_set_timer(dsrc, dispatch_time(DISPATCH_TIME_NOW, 0), NSEC_PER_SEC / 2, NSEC_PER_SEC);
354 dispatch_block_t event_block = ^{
355 memory->_readable = true;
356 if (!memory->_rsuspended) {
357 dispatch_suspend(dsrc);
358 // CFLog(5, CFSTR("suspend %p due to read event block"), memory);
359 memory->_rsuspended = true;
361 if (shared->_source) {
362 CFRunLoopSourceSignal(shared->_source);
363 _CFRunLoopSourceWakeUpRunLoops(shared->_source);
366 dispatch_block_t cancel_block = ^{
367 shared->_rdsrc = NULL;
369 if (0 == shared->_refCnt) {
370 if (shared->_closeFD) {
371 // thoroughly stop anything else from using the fd
372 (void)shutdown(shared->_socket, SHUT_RDWR);
373 int nullfd = open("/dev/null", O_RDONLY);
374 dup2(nullfd, shared->_socket);
376 close(shared->_socket);
380 dispatch_release(dsrc);
382 dispatch_source_set_event_handler(dsrc, event_block);
383 dispatch_source_set_cancel_handler(dsrc, cancel_block);
384 shared->_rdsrc = dsrc;
386 if (memory->_wantWrite || memory->_wantConnect) {
387 dispatch_source_t dsrc = NULL;
389 dsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, ufd, 0, __sockQueue());
391 dsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, __sockQueue());
392 dispatch_source_set_timer(dsrc, dispatch_time(DISPATCH_TIME_NOW, 0), NSEC_PER_SEC / 2, NSEC_PER_SEC);
394 dispatch_block_t event_block = ^{
395 memory->_writeable = true;
396 if (!memory->_wsuspended) {
397 dispatch_suspend(dsrc);
398 // CFLog(5, CFSTR("suspend %p due to write event block"), memory);
399 memory->_wsuspended = true;
401 if (shared->_source) {
402 CFRunLoopSourceSignal(shared->_source);
403 _CFRunLoopSourceWakeUpRunLoops(shared->_source);
406 dispatch_block_t cancel_block = ^{
407 shared->_wrsrc = NULL;
409 if (0 == shared->_refCnt) {
410 if (shared->_closeFD) {
411 // thoroughly stop anything else from using the fd
412 (void)shutdown(shared->_socket, SHUT_RDWR);
413 int nullfd = open("/dev/null", O_RDONLY);
414 dup2(nullfd, shared->_socket);
416 close(shared->_socket);
420 dispatch_release(dsrc);
422 dispatch_source_set_event_handler(dsrc, event_block);
423 dispatch_source_set_cancel_handler(dsrc, cancel_block);
424 shared->_wrsrc = dsrc;
427 if (shared->_rdsrc) {
430 if (shared->_wrsrc) {
434 memory->_state = kCFSocketStateReady;
435 CFArrayAppendValue(__CFAllSockets, memory);
438 // CFLog(5, CFSTR("CFSocketCreateWithNative(): created socket %p with callbacks 0x%x"), sock, callBackTypes);
439 if (sock && !CFSocketIsValid(sock)) { // must do this outside lock to avoid deadlock
446 CFSocketNativeHandle CFSocketGetNative(CFSocketRef sock) {
447 CHECK_FOR_FORK_RET(INVALID_SOCKET);
448 __CFGenericValidateType(sock, CFSocketGetTypeID());
449 return sock->_shared ? sock->_shared->_socket : INVALID_SOCKET;
452 void CFSocketGetContext(CFSocketRef sock, CFSocketContext *context) {
453 __CFGenericValidateType(sock, CFSocketGetTypeID());
454 CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__);
455 objc_memmove_collectable(context, &sock->_context, sizeof(CFSocketContext));
458 CFDataRef CFSocketCopyAddress(CFSocketRef sock) {
459 CHECK_FOR_FORK_RET(NULL);
460 __CFGenericValidateType(sock, CFSocketGetTypeID());
461 __block CFDataRef result = NULL;
462 dispatch_sync(__sockQueue(), ^{
463 if (!sock->_address) {
464 if (!__CFSocketIsValid(sock)) return;
465 uint8_t name[MAX_SOCKADDR_LEN];
466 socklen_t namelen = sizeof(name);
467 int ret = getsockname(sock->_shared->_socket, (struct sockaddr *)name, (socklen_t *)&namelen);
468 if (0 == ret && 0 < namelen) {
469 sock->_address = CFDataCreate(CFGetAllocator(sock), name, namelen);
472 result = sock->_address ? (CFDataRef)CFRetain(sock->_address) : NULL;
477 CFDataRef CFSocketCopyPeerAddress(CFSocketRef sock) {
478 CHECK_FOR_FORK_RET(NULL);
479 __CFGenericValidateType(sock, CFSocketGetTypeID());
480 __block CFDataRef result = NULL;
481 dispatch_sync(__sockQueue(), ^{
482 if (!sock->_peerAddress) {
483 if (!__CFSocketIsValid(sock)) return;
484 uint8_t name[MAX_SOCKADDR_LEN];
485 socklen_t namelen = sizeof(name);
486 int ret = getpeername(sock->_shared->_socket, (struct sockaddr *)name, (socklen_t *)&namelen);
487 if (0 == ret && 0 < namelen) {
488 sock->_peerAddress = CFDataCreate(CFGetAllocator(sock), name, namelen);
491 result = sock->_peerAddress ? (CFDataRef)CFRetain(sock->_peerAddress) : NULL;
496 CFOptionFlags CFSocketGetSocketFlags(CFSocketRef sock) {
498 __CFGenericValidateType(sock, CFSocketGetTypeID());
499 __block CFOptionFlags flags = 0;
500 dispatch_sync(__sockQueue(), ^{
501 if (sock->_reenableRead) flags |= sock->_wantReadType; // flags are same as types here
502 if (sock->_reenableWrite) flags |= kCFSocketAutomaticallyReenableWriteCallBack;
503 if (sock->_leaveErrors) flags |= kCFSocketLeaveErrors;
504 if (sock->_closeOnInvalidate) flags |= kCFSocketCloseOnInvalidate;
509 void CFSocketSetSocketFlags(CFSocketRef sock, CFOptionFlags flags) {
511 // CFLog(5, CFSTR("CFSocketSetSocketFlags(%p, 0x%x) starting"), sock, flags);
512 __CFGenericValidateType(sock, CFSocketGetTypeID());
513 dispatch_sync(__sockQueue(), ^{
514 sock->_reenableRead = (sock->_wantReadType && ((flags & 0x3) == sock->_wantReadType)) ? true : false;
515 sock->_reenableWrite = (sock->_wantWrite && (flags & kCFSocketAutomaticallyReenableWriteCallBack)) ? true : false;
516 sock->_leaveErrors = (flags & kCFSocketLeaveErrors) ? true : false;
517 sock->_closeOnInvalidate = (flags & kCFSocketCloseOnInvalidate) ? true : false;
518 if (sock->_shared) sock->_shared->_closeFD = sock->_closeOnInvalidate;
520 // CFLog(5, CFSTR("CFSocketSetSocketFlags(%p, 0x%x) done"), sock, flags);
523 void CFSocketEnableCallBacks(CFSocketRef sock, CFOptionFlags callBackTypes) {
524 CHECK_FOR_FORK_RET();
525 __CFGenericValidateType(sock, CFSocketGetTypeID());
526 // CFLog(5, CFSTR("CFSocketEnableCallBacks(%p, 0x%x) starting"), sock, callBackTypes);
527 dispatch_sync(__sockQueue(), ^{
528 if (!__CFSocketIsValid(sock)) return;
529 if (sock->_wantReadType && (callBackTypes & 0x3) == sock->_wantReadType) {
530 if (sockfd_is_readable(sock->_shared->_socket)) {
531 sock->_readable = true;
532 // CFLog(5, CFSTR("CFSocketEnableCallBacks(%p, 0x%x) socket is readable"), sock, callBackTypes);
533 if (!sock->_rsuspended) {
534 dispatch_suspend(sock->_shared->_rdsrc);
535 sock->_rsuspended = true;
537 // If the source exists, but is now invalid, this next stuff is relatively harmless.
538 if (sock->_shared->_source) {
539 CFRunLoopSourceSignal(sock->_shared->_source);
540 _CFRunLoopSourceWakeUpRunLoops(sock->_shared->_source);
542 } else if (sock->_rsuspended && sock->_shared->_rdsrc) {
543 sock->_rsuspended = false;
544 dispatch_resume(sock->_shared->_rdsrc);
546 sock->_readDisabled = false;
548 if (sock->_wantWrite && (callBackTypes & kCFSocketWriteCallBack)) {
549 if (sockfd_is_writeable(sock->_shared->_socket)) {
550 sock->_writeable = true;
551 if (!sock->_wsuspended) {
552 dispatch_suspend(sock->_shared->_wrsrc);
553 sock->_wsuspended = true;
555 // If the source exists, but is now invalid, this next stuff is relatively harmless.
556 if (sock->_shared->_source) {
557 CFRunLoopSourceSignal(sock->_shared->_source);
558 _CFRunLoopSourceWakeUpRunLoops(sock->_shared->_source);
560 } else if (sock->_wsuspended && sock->_shared->_wrsrc) {
561 sock->_wsuspended = false;
562 dispatch_resume(sock->_shared->_wrsrc);
564 sock->_writeDisabled = false;
566 if (sock->_wantConnect && !sock->_connected && (callBackTypes & kCFSocketConnectCallBack)) {
567 if (sockfd_is_writeable(sock->_shared->_socket)) {
568 sock->_writeable = true;
569 if (!sock->_wsuspended) {
570 dispatch_suspend(sock->_shared->_wrsrc);
571 sock->_wsuspended = true;
573 // If the source exists, but is now invalid, this next stuff is relatively harmless.
574 if (sock->_shared->_source) {
575 CFRunLoopSourceSignal(sock->_shared->_source);
576 _CFRunLoopSourceWakeUpRunLoops(sock->_shared->_source);
578 } else if (sock->_wsuspended && sock->_shared->_wrsrc) {
579 sock->_wsuspended = false;
580 dispatch_resume(sock->_shared->_wrsrc);
582 sock->_connectDisabled = false;
585 // CFLog(5, CFSTR("CFSocketEnableCallBacks(%p, 0x%x) done"), sock, callBackTypes);
588 void CFSocketDisableCallBacks(CFSocketRef sock, CFOptionFlags callBackTypes) {
589 CHECK_FOR_FORK_RET();
590 __CFGenericValidateType(sock, CFSocketGetTypeID());
591 // CFLog(5, CFSTR("CFSocketDisableCallBacks(%p, 0x%x) starting"), sock, callBackTypes);
592 dispatch_sync(__sockQueue(), ^{
593 if (!__CFSocketIsValid(sock)) return;
594 if (sock->_wantReadType && (callBackTypes & 0x3) == sock->_wantReadType) {
595 if (!sock->_rsuspended && sock->_shared->_rdsrc) {
596 dispatch_suspend(sock->_shared->_rdsrc);
597 sock->_rsuspended = true;
599 sock->_readDisabled = true;
601 if (sock->_wantWrite && (callBackTypes & kCFSocketWriteCallBack)) {
602 if (!sock->_wsuspended && sock->_shared->_wrsrc) {
603 dispatch_suspend(sock->_shared->_wrsrc);
604 sock->_wsuspended = true;
606 sock->_writeDisabled = true;
608 if (sock->_wantConnect && !sock->_connected && (callBackTypes & kCFSocketConnectCallBack)) {
609 if (!sock->_wsuspended && sock->_shared->_wrsrc) {
610 dispatch_suspend(sock->_shared->_wrsrc);
611 sock->_wsuspended = true;
613 sock->_connectDisabled = true;
616 // CFLog(5, CFSTR("CFSocketDisableCallBacks(%p, 0x%x) done"), sock, callBackTypes);
619 void CFSocketInvalidate(CFSocketRef sock) {
620 CHECK_FOR_FORK_RET();
621 __CFGenericValidateType(sock, CFSocketGetTypeID());
623 // CFLog(5, CFSTR("CFSocketInvalidate(%p) starting"), sock);
624 __block CFRunLoopSourceRef source = NULL;
625 __block Boolean wasReady = false;
626 dispatch_sync(__sockQueue(), ^{
627 wasReady = (sock->_state == kCFSocketStateReady);
629 sock->_state = kCFSocketStateInvalidating;
631 for (CFIndex idx = 0, cnt = CFArrayGetCount(__CFAllSockets); idx < cnt; idx++) {
632 CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(__CFAllSockets, idx);
634 CFArrayRemoveValueAtIndex(__CFAllSockets, idx);
638 if (sock->_shared->_rdsrc) {
639 dispatch_source_cancel(sock->_shared->_rdsrc);
640 if (sock->_rsuspended) {
641 sock->_rsuspended = false;
642 dispatch_resume(sock->_shared->_rdsrc);
645 if (sock->_shared->_wrsrc) {
646 dispatch_source_cancel(sock->_shared->_wrsrc);
647 if (sock->_wsuspended) {
648 sock->_wsuspended = false;
649 dispatch_resume(sock->_shared->_wrsrc);
652 source = sock->_shared->_source;
653 sock->_shared->_source = NULL;
654 sock->_shared->_refCnt--;
655 if (0 == sock->_shared->_refCnt) {
656 if (sock->_shared->_closeFD) {
657 // thoroughly stop anything else from using the fd
658 (void)shutdown(sock->_shared->_socket, SHUT_RDWR);
659 int nullfd = open("/dev/null", O_RDONLY);
660 dup2(nullfd, sock->_shared->_socket);
662 close(sock->_shared->_socket);
666 sock->_shared = NULL;
670 if (NULL != source) {
671 CFRunLoopSourceInvalidate(source);
674 void *info = sock->_context.info;
675 sock->_context.info = NULL;
676 if (sock->_context.release) {
677 sock->_context.release(info);
679 sock->_state = kCFSocketStateInvalid;
682 // CFLog(5, CFSTR("CFSocketInvalidate(%p) done%s"), sock, wasReady ? " -- done on this thread" : "");
686 Boolean CFSocketIsValid(CFSocketRef sock) {
687 __CFGenericValidateType(sock, CFSocketGetTypeID());
688 if (!__CFSocketIsValid(sock)) return false;
690 int ret = sock->_shared ? fstat(sock->_shared->_socket, &statbuf) : -1;
692 CFSocketInvalidate(sock);
699 static void __CFSocketPerform(void *info) { // CFRunLoop should only call this on one thread at a time
700 CHECK_FOR_FORK_RET();
701 CFSocketRef sock = (CFSocketRef)info;
703 // CFLog(5, CFSTR("__CFSocketPerform(%p) starting '%@'"), sock, sock);
704 __block Boolean doRead = false, doWrite = false, doConnect = false, isValid = false;
705 __block int fd = INVALID_SOCKET;
706 __block SInt32 errorCode = 0;
707 __block int new_fd = INVALID_SOCKET;
708 __block CFDataRef address = NULL;
709 __block CFMutableDataRef data = NULL;
710 __block void *context_info = NULL;
711 __block void (*context_release)(const void *) = NULL;
712 dispatch_sync(__sockQueue(), ^{
713 isValid = __CFSocketIsValid(sock);
714 if (!isValid) return;
715 fd = sock->_shared->_socket;
716 doRead = sock->_readable && sock->_wantReadType && !sock->_readDisabled;
718 sock->_readable = false;
719 doRead = sockfd_is_readable(fd);
720 // if (!doRead) CFLog(5, CFSTR("__CFSocketPerform(%p) socket is not actually readable"), sock);
722 doWrite = sock->_writeable && sock->_wantWrite && !sock->_writeDisabled;
723 doConnect = sock->_writeable && sock->_wantConnect && !sock->_connectDisabled && !sock->_connected;
724 if (doWrite || doConnect) {
725 sock->_writeable = false;
726 if (doWrite) doWrite = sockfd_is_writeable(fd);
727 if (doConnect) doConnect = sockfd_is_writeable(fd);
729 if (!sock->_leaveErrors && (doWrite || doConnect)) { // not on read, for whatever reason
730 int errorSize = sizeof(errorCode);
731 int ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&errorCode, (socklen_t *)&errorSize);
732 if (0 != ret) errorCode = 0;
733 sock->_error = errorCode;
735 sock->_connected = true;
736 // CFLog(5, CFSTR("__CFSocketPerform(%p) doing %d %d %d"), sock, doRead, doWrite, doConnect);
738 switch (sock->_wantReadType) {
739 case kCFSocketReadCallBack:
741 case kCFSocketAcceptCallBack: {
742 uint8_t name[MAX_SOCKADDR_LEN];
743 socklen_t namelen = sizeof(name);
744 new_fd = accept(fd, (struct sockaddr *)name, (socklen_t *)&namelen);
745 if (INVALID_SOCKET != new_fd) {
746 address = CFDataCreate(CFGetAllocator(sock), name, namelen);
750 case kCFSocketDataCallBack: {
751 uint8_t name[MAX_SOCKADDR_LEN];
752 socklen_t namelen = sizeof(name);
754 int ret = ioctlsocket(fd, FIONREAD, &avail);
755 if (ret < 0 || avail < 256) avail = 256;
756 if ((1 << 20) < avail) avail = (1 << 20);
757 data = CFDataCreateMutable(CFGetAllocator(sock), 0);
758 CFDataSetLength(data, avail);
759 ssize_t len = recvfrom(fd, CFDataGetMutableBytePtr(data), avail, 0, (struct sockaddr *)name, (socklen_t *)&namelen);
760 CFIndex datalen = (len < 0) ? 0 : len;
761 CFDataSetLength(data, datalen);
763 address = CFDataCreate(CFGetAllocator(sock), name, namelen);
764 } else if (sock->_connOriented) {
765 // cannot call CFSocketCopyPeerAddress(), or deadlock
766 if (!sock->_peerAddress) {
767 uint8_t name[MAX_SOCKADDR_LEN];
768 socklen_t namelen = sizeof(name);
769 int ret = getpeername(sock->_shared->_socket, (struct sockaddr *)name, (socklen_t *)&namelen);
770 if (0 == ret && 0 < namelen) {
771 sock->_peerAddress = CFDataCreate(CFGetAllocator(sock), name, namelen);
774 address = sock->_peerAddress ? (CFDataRef)CFRetain(sock->_peerAddress) : NULL;
776 if (NULL == address) {
777 address = CFDataCreate(CFGetAllocator(sock), NULL, 0);
783 if (sock->_reenableRead) {
784 // CFLog(5, CFSTR("__CFSocketPerform(%p) reenabling read %d %p"), sock, sock->_rsuspended, sock->_shared->_rdsrc);
785 if (sock->_rsuspended && sock->_shared->_rdsrc) {
786 sock->_rsuspended = false;
787 dispatch_resume(sock->_shared->_rdsrc);
790 if (sock->_reenableWrite) {
791 if (sock->_wsuspended && sock->_shared->_wrsrc) {
792 sock->_wsuspended = false;
793 dispatch_resume(sock->_shared->_wrsrc);
796 if (sock->_context.retain && (doConnect || doRead || doWrite)) {
797 context_info = (void *)sock->_context.retain(sock->_context.info);
798 context_release = sock->_context.release;
800 context_info = sock->_context.info;
803 // CFLog(5, CFSTR("__CFSocketPerform(%p) isValid:%d, doRead:%d, doWrite:%d, doConnect:%d error:%d"), sock, isValid, doRead, doWrite, doConnect, errorCode);
804 if (!isValid || !(doConnect || doRead || doWrite)) return;
806 Boolean calledOut = false;
808 if (sock->_callout) sock->_callout(sock, kCFSocketConnectCallBack, NULL, (0 != errorCode) ? &errorCode : NULL, context_info);
811 if (doRead && (!calledOut || __CFSocketIsValid(sock))) {
812 switch (sock->_wantReadType) {
813 case kCFSocketReadCallBack:
814 if (sock->_callout) sock->_callout(sock, kCFSocketReadCallBack, NULL, NULL, context_info);
817 case kCFSocketAcceptCallBack:
818 if (INVALID_SOCKET != new_fd) {
819 if (sock->_callout) sock->_callout(sock, kCFSocketAcceptCallBack, address, &new_fd, context_info);
823 case kCFSocketDataCallBack:
824 if (sock->_callout) sock->_callout(sock, kCFSocketDataCallBack, address, data, context_info);
829 if (doWrite && (!calledOut || __CFSocketIsValid(sock))) {
830 if (0 == errorCode) {
831 if (sock->_callout) sock->_callout(sock, kCFSocketWriteCallBack, NULL, NULL, context_info);
836 if (data && 0 == CFDataGetLength(data)) CFSocketInvalidate(sock);
837 if (address) CFRelease(address);
838 if (data) CFRelease(data);
839 if (context_release) {
840 context_release(context_info);
843 CHECK_FOR_FORK_RET();
844 // CFLog(5, CFSTR("__CFSocketPerform(%p) done"), sock);
847 static void __CFSocketSchedule(void *info, CFRunLoopRef rl, CFStringRef mode) {
848 CFSocketRef sock = (CFSocketRef)info;
849 int32_t newVal = OSAtomicIncrement32Barrier(&sock->_runLoopCounter);
850 if (1 == newVal) { // on a transition from 0->1, the old code forced all desired callbacks enabled
851 CFOptionFlags types = sock->_wantReadType | (sock->_wantWrite ? kCFSocketWriteCallBack : 0) | (sock->_wantConnect ? kCFSocketConnectCallBack : 0);
852 CFSocketEnableCallBacks(sock, types);
857 static void __CFSocketCancel(void *info, CFRunLoopRef rl, CFStringRef mode) {
858 CFSocketRef sock = (CFSocketRef)info;
859 OSAtomicDecrement32Barrier(&sock->_runLoopCounter);
863 CFRunLoopSourceRef CFSocketCreateRunLoopSource(CFAllocatorRef allocator, CFSocketRef sock, CFIndex order) {
864 CHECK_FOR_FORK_RET(NULL);
865 __CFGenericValidateType(sock, CFSocketGetTypeID());
866 if (!CFSocketIsValid(sock)) return NULL;
867 __block CFRunLoopSourceRef result = NULL;
868 dispatch_sync(__sockQueue(), ^{
869 if (!__CFSocketIsValid(sock)) return;
870 if (NULL != sock->_shared->_source && !CFRunLoopSourceIsValid(sock->_shared->_source)) {
871 CFRelease(sock->_shared->_source);
872 sock->_shared->_source = NULL;
874 if (NULL == sock->_shared->_source) {
875 CFRunLoopSourceContext context;
877 context.info = (void *)sock;
878 context.retain = (const void *(*)(const void *))CFRetain;
879 context.release = (void (*)(const void *))CFRelease;
880 context.copyDescription = (CFStringRef (*)(const void *))__CFSocketCopyDescription;
881 context.equal = NULL;
883 context.schedule = __CFSocketSchedule;
884 context.cancel = __CFSocketCancel;
885 context.perform = __CFSocketPerform;
886 sock->_shared->_source = CFRunLoopSourceCreate(allocator, order, (CFRunLoopSourceContext *)&context);
887 if (sock->_shared->_source) {
888 if (sock->_wantReadType) {
889 if (sockfd_is_readable(sock->_shared->_socket)) {
890 sock->_readable = true;
891 if (!sock->_rsuspended) {
892 dispatch_suspend(sock->_shared->_rdsrc);
893 sock->_rsuspended = true;
895 if (sock->_shared->_source) {
896 CFRunLoopSourceSignal(sock->_shared->_source);
897 _CFRunLoopSourceWakeUpRunLoops(sock->_shared->_source);
899 } else if (sock->_rsuspended && sock->_shared->_rdsrc) {
900 sock->_rsuspended = false;
901 dispatch_resume(sock->_shared->_rdsrc);
904 if (sock->_wantWrite || (sock->_wantConnect && !sock->_connected)) {
905 if (sockfd_is_writeable(sock->_shared->_socket)) {
906 sock->_writeable = true;
907 if (!sock->_wsuspended) {
908 dispatch_suspend(sock->_shared->_wrsrc);
909 sock->_wsuspended = true;
911 if (sock->_shared->_source) {
912 CFRunLoopSourceSignal(sock->_shared->_source);
913 _CFRunLoopSourceWakeUpRunLoops(sock->_shared->_source);
915 } else if (sock->_wsuspended && sock->_shared->_wrsrc) {
916 sock->_wsuspended = false;
917 dispatch_resume(sock->_shared->_wrsrc);
922 result = sock->_shared->_source ? (CFRunLoopSourceRef)CFRetain(sock->_shared->_source) : NULL;
924 // CFLog(5, CFSTR("CFSocketCreateRunLoopSource(%p) => %p"), sock, result);
929 void __CFSocketSetSocketReadBufferAttrs(CFSocketRef s, CFTimeInterval timeout, CFIndex length) {
932 CFIndex __CFSocketRead(CFSocketRef s, UInt8* buffer, CFIndex length, int* error) {
934 int ret = read(CFSocketGetNative(s), buffer, length);
941 Boolean __CFSocketGetBytesAvailable(CFSocketRef s, CFIndex* ctBytesAvailable) {
943 int ret = ioctlsocket(CFSocketGetNative(s), FIONREAD, &bytesAvailable);
944 if (ret < 0) return false;
945 *ctBytesAvailable = (CFIndex)bytesAvailable;
950 #else /* not NEW_SOCKET */
953 #include <CoreFoundation/CFSocket.h>
954 #include <sys/types.h>
957 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
958 #include <sys/sysctl.h>
963 #include <CoreFoundation/CFArray.h>
964 #include <CoreFoundation/CFData.h>
965 #include <CoreFoundation/CFDictionary.h>
966 #include <CoreFoundation/CFRunLoop.h>
967 #include <CoreFoundation/CFString.h>
968 #include <CoreFoundation/CFPropertyList.h>
969 #include "CFInternal.h"
971 #if DEPLOYMENT_TARGET_WINDOWS
973 #define EINPROGRESS WSAEINPROGRESS
975 // redefine this to the winsock error in this file
977 #define EBADF WSAENOTSOCK
980 #define NFDBITS (sizeof(int32_t) * NBBY)
982 typedef int32_t fd_mask
;
983 typedef int socklen_t
;
985 #define gettimeofday _NS_gettimeofday
986 CF_PRIVATE
int _NS_gettimeofday(struct timeval
*tv
, struct timezone
*tz
);
988 // although this is only used for debug info, we define it for compatibility
989 #define timersub(tvp, uvp, vvp) \
991 (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
992 (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
993 if ((vvp)->tv_usec < 0) { \
995 (vvp)->tv_usec += 1000000; \
1000 #endif // DEPLOYMENT_TARGET_WINDOWS
1003 // On Mach we use a v0 RunLoopSource to make client callbacks. That source is signalled by a
1004 // separate SocketManager thread who uses select() to watch the sockets' fds.
1006 //#define LOG_CFSOCKET
1008 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1009 #define INVALID_SOCKET (CFSocketNativeHandle)(-1)
1010 #define closesocket(a) close((a))
1011 #define ioctlsocket(a,b,c) ioctl((a),(b),(c))
1014 CF_INLINE
int __CFSocketLastError(void) {
1015 #if DEPLOYMENT_TARGET_WINDOWS
1016 return WSAGetLastError();
1018 return thread_errno();
1022 CF_INLINE CFIndex
__CFSocketFdGetSize(CFDataRef fdSet
) {
1023 return NBBY
* CFDataGetLength(fdSet
);
1026 CF_INLINE Boolean
__CFSocketFdSet(CFSocketNativeHandle sock
, CFMutableDataRef fdSet
) {
1027 /* returns true if a change occurred, false otherwise */
1028 Boolean retval
= false;
1029 if (INVALID_SOCKET
!= sock
&& 0 <= sock
) {
1030 CFIndex numFds
= NBBY
* CFDataGetLength(fdSet
);
1032 if (sock
>= numFds
) {
1033 CFIndex oldSize
= numFds
/ NFDBITS
, newSize
= (sock
+ NFDBITS
) / NFDBITS
, changeInBytes
= (newSize
- oldSize
) * sizeof(fd_mask
);
1034 CFDataIncreaseLength(fdSet
, changeInBytes
);
1035 fds_bits
= (fd_mask
*)CFDataGetMutableBytePtr(fdSet
);
1036 memset(fds_bits
+ oldSize
, 0, changeInBytes
);
1038 fds_bits
= (fd_mask
*)CFDataGetMutableBytePtr(fdSet
);
1040 if (!FD_ISSET(sock
, (fd_set
*)fds_bits
)) {
1042 FD_SET(sock
, (fd_set
*)fds_bits
);
1049 #define MAX_SOCKADDR_LEN 256
1050 #define MAX_DATA_SIZE 65535
1051 #define MAX_CONNECTION_ORIENTED_DATA_SIZE 32768
1053 /* locks are to be acquired in the following order:
1054 (1) __CFAllSocketsLock
1055 (2) an individual CFSocket's lock
1056 (3) __CFActiveSocketsLock
1058 static CFSpinLock_t __CFAllSocketsLock
= CFSpinLockInit
; /* controls __CFAllSockets */
1059 static CFMutableDictionaryRef __CFAllSockets
= NULL
;
1060 static CFSpinLock_t __CFActiveSocketsLock
= CFSpinLockInit
; /* controls __CFRead/WriteSockets, __CFRead/WriteSocketsFds, __CFSocketManagerThread, and __CFSocketManagerIteration */
1061 static volatile UInt32 __CFSocketManagerIteration
= 0;
1062 static CFMutableArrayRef __CFWriteSockets
= NULL
;
1063 static CFMutableArrayRef __CFReadSockets
= NULL
;
1064 static CFMutableDataRef __CFWriteSocketsFds
= NULL
;
1065 static CFMutableDataRef __CFReadSocketsFds
= NULL
;
1066 static CFDataRef zeroLengthData
= NULL
;
1067 static Boolean __CFReadSocketsTimeoutInvalid
= true; /* rebuild the timeout value before calling select */
1069 static CFSocketNativeHandle __CFWakeupSocketPair
[2] = {INVALID_SOCKET
, INVALID_SOCKET
};
1070 static void *__CFSocketManagerThread
= NULL
;
1072 static void __CFSocketDoCallback(CFSocketRef s
, CFDataRef data
, CFDataRef address
, CFSocketNativeHandle sock
);
1075 CFRuntimeBase _base
;
1077 unsigned client
:8; // flags set by client (reenable, CloseOnInvalidate)
1078 unsigned disabled
:8; // flags marking disabled callbacks
1079 unsigned connected
:1; // Are we connected yet? (also true for connectionless sockets)
1080 unsigned writableHint
:1; // Did the polling the socket show it to be writable?
1081 unsigned closeSignaled
:1; // Have we seen FD_CLOSE? (only used on Win32)
1085 CFSpinLock_t _writeLock
;
1086 CFSocketNativeHandle _socket
; /* immutable */
1090 CFDataRef _peerAddress
;
1091 SInt32 _socketSetCount
;
1092 CFRunLoopSourceRef _source0
; // v0 RLS, messaged from SocketMgr
1093 CFMutableArrayRef _runLoops
;
1094 CFSocketCallBack _callout
; /* immutable */
1095 CFSocketContext _context
; /* immutable */
1096 CFMutableArrayRef _dataQueue
; // queues to pass data from SocketMgr thread
1097 CFMutableArrayRef _addressQueue
;
1099 struct timeval _readBufferTimeout
;
1100 CFMutableDataRef _readBuffer
;
1101 CFIndex _bytesToBuffer
; /* is length of _readBuffer */
1102 CFIndex _bytesToBufferPos
; /* where the next _CFSocketRead starts from */
1103 CFIndex _bytesToBufferReadPos
; /* Where the buffer will next be read into (always after _bytesToBufferPos, but less than _bytesToBuffer) */
1105 int _bufferedReadError
;
1107 CFMutableDataRef _leftoverBytes
;
1110 /* Bit 6 in the base reserved bits is used for write-signalled state (mutable) */
1111 /* Bit 5 in the base reserved bits is used for read-signalled state (mutable) */
1112 /* Bit 4 in the base reserved bits is used for invalid state (mutable) */
1113 /* Bits 0-3 in the base reserved bits are used for callback types (immutable) */
1114 /* Of this, bits 0-1 are used for the read callback type. */
1116 CF_INLINE Boolean
__CFSocketIsWriteSignalled(CFSocketRef s
) {
1117 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 6, 6);
1120 CF_INLINE
void __CFSocketSetWriteSignalled(CFSocketRef s
) {
1121 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 6, 6, 1);
1124 CF_INLINE
void __CFSocketUnsetWriteSignalled(CFSocketRef s
) {
1125 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 6, 6, 0);
1128 CF_INLINE Boolean
__CFSocketIsReadSignalled(CFSocketRef s
) {
1129 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 5, 5);
1132 CF_INLINE
void __CFSocketSetReadSignalled(CFSocketRef s
) {
1133 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 5, 5, 1);
1136 CF_INLINE
void __CFSocketUnsetReadSignalled(CFSocketRef s
) {
1137 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 5, 5, 0);
1140 CF_INLINE Boolean
__CFSocketIsValid(CFSocketRef s
) {
1141 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 4, 4);
1144 CF_INLINE
void __CFSocketSetValid(CFSocketRef s
) {
1145 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 4, 4, 1);
1148 CF_INLINE
void __CFSocketUnsetValid(CFSocketRef s
) {
1149 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 4, 4, 0);
1152 CF_INLINE
uint8_t __CFSocketCallBackTypes(CFSocketRef s
) {
1153 return (uint8_t)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 3, 0);
1156 CF_INLINE
uint8_t __CFSocketReadCallBackType(CFSocketRef s
) {
1157 return (uint8_t)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 1, 0);
1160 CF_INLINE
void __CFSocketSetCallBackTypes(CFSocketRef s
, uint8_t types
) {
1161 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 3, 0, types
& 0xF);
1164 CF_INLINE
void __CFSocketLock(CFSocketRef s
) {
1165 __CFSpinLock(&(s
->_lock
));
1168 CF_INLINE
void __CFSocketUnlock(CFSocketRef s
) {
1169 __CFSpinUnlock(&(s
->_lock
));
1172 CF_INLINE Boolean
__CFSocketIsConnectionOriented(CFSocketRef s
) {
1173 return (SOCK_STREAM
== s
->_socketType
|| SOCK_SEQPACKET
== s
->_socketType
);
1176 CF_INLINE Boolean
__CFSocketIsScheduled(CFSocketRef s
) {
1177 return (s
->_socketSetCount
> 0);
1180 CF_INLINE
void __CFSocketEstablishAddress(CFSocketRef s
) {
1181 /* socket should already be locked */
1182 uint8_t name
[MAX_SOCKADDR_LEN
];
1183 int namelen
= sizeof(name
);
1184 if (__CFSocketIsValid(s
) && NULL
== s
->_address
&& INVALID_SOCKET
!= s
->_socket
&& 0 == getsockname(s
->_socket
, (struct sockaddr
*)name
, (socklen_t
*)&namelen
) && NULL
!= name
&& 0 < namelen
) {
1185 s
->_address
= CFDataCreate(CFGetAllocator(s
), name
, namelen
);
1189 CF_INLINE
void __CFSocketEstablishPeerAddress(CFSocketRef s
) {
1190 /* socket should already be locked */
1191 uint8_t name
[MAX_SOCKADDR_LEN
];
1192 int namelen
= sizeof(name
);
1193 if (__CFSocketIsValid(s
) && NULL
== s
->_peerAddress
&& INVALID_SOCKET
!= s
->_socket
&& 0 == getpeername(s
->_socket
, (struct sockaddr
*)name
, (socklen_t
*)&namelen
) && NULL
!= name
&& 0 < namelen
) {
1194 s
->_peerAddress
= CFDataCreate(CFGetAllocator(s
), name
, namelen
);
1198 static Boolean
__CFNativeSocketIsValid(CFSocketNativeHandle sock
) {
1199 #if DEPLOYMENT_TARGET_WINDOWS
1200 SInt32 errorCode
= 0;
1201 int errorSize
= sizeof(errorCode
);
1202 return !(0 != getsockopt(sock
, SOL_SOCKET
, SO_ERROR
, (char *)&errorCode
, &errorSize
) && __CFSocketLastError() == WSAENOTSOCK
);
1204 SInt32 flags
= fcntl(sock
, F_GETFL
, 0);
1205 return !(0 > flags
&& EBADF
== __CFSocketLastError());
1209 CF_INLINE Boolean
__CFSocketFdClr(CFSocketNativeHandle sock
, CFMutableDataRef fdSet
) {
1210 /* returns true if a change occurred, false otherwise */
1211 Boolean retval
= false;
1212 if (INVALID_SOCKET
!= sock
&& 0 <= sock
) {
1213 CFIndex numFds
= NBBY
* CFDataGetLength(fdSet
);
1215 if (sock
< numFds
) {
1216 fds_bits
= (fd_mask
*)CFDataGetMutableBytePtr(fdSet
);
1217 if (FD_ISSET(sock
, (fd_set
*)fds_bits
)) {
1219 FD_CLR(sock
, (fd_set
*)fds_bits
);
1226 static SInt32
__CFSocketCreateWakeupSocketPair(void) {
1227 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1230 error
= socketpair(PF_LOCAL
, SOCK_DGRAM
, 0, __CFWakeupSocketPair
);
1231 if (0 <= error
) error
= fcntl(__CFWakeupSocketPair
[0], F_SETFD
, FD_CLOEXEC
);
1232 if (0 <= error
) error
= fcntl(__CFWakeupSocketPair
[1], F_SETFD
, FD_CLOEXEC
);
1234 closesocket(__CFWakeupSocketPair
[0]);
1235 closesocket(__CFWakeupSocketPair
[1]);
1236 __CFWakeupSocketPair
[0] = INVALID_SOCKET
;
1237 __CFWakeupSocketPair
[1] = INVALID_SOCKET
;
1242 struct sockaddr_in address
[2];
1243 int namelen
= sizeof(struct sockaddr_in
);
1244 for (i
= 0; i
< 2; i
++) {
1245 __CFWakeupSocketPair
[i
] = socket(PF_INET
, SOCK_DGRAM
, 0);
1246 memset(&(address
[i
]), 0, sizeof(struct sockaddr_in
));
1247 address
[i
].sin_family
= AF_INET
;
1248 address
[i
].sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
1249 if (0 <= error
) error
= bind(__CFWakeupSocketPair
[i
], (struct sockaddr
*)&(address
[i
]), sizeof(struct sockaddr_in
));
1250 if (0 <= error
) error
= getsockname(__CFWakeupSocketPair
[i
], (struct sockaddr
*)&(address
[i
]), &namelen
);
1251 if (sizeof(struct sockaddr_in
) != namelen
) error
= -1;
1253 if (0 <= error
) error
= connect(__CFWakeupSocketPair
[0], (struct sockaddr
*)&(address
[1]), sizeof(struct sockaddr_in
));
1254 if (0 <= error
) error
= connect(__CFWakeupSocketPair
[1], (struct sockaddr
*)&(address
[0]), sizeof(struct sockaddr_in
));
1256 closesocket(__CFWakeupSocketPair
[0]);
1257 closesocket(__CFWakeupSocketPair
[1]);
1258 __CFWakeupSocketPair
[0] = INVALID_SOCKET
;
1259 __CFWakeupSocketPair
[1] = INVALID_SOCKET
;
1262 #if defined(LOG_CFSOCKET)
1263 fprintf(stdout
, "wakeup socket pair is %d / %d\n", __CFWakeupSocketPair
[0], __CFWakeupSocketPair
[1]);
1269 // Version 0 RunLoopSources set a mask in an FD set to control what socket activity we hear about.
1270 // Changes to the master fs_sets occur via these 4 functions.
1271 CF_INLINE Boolean
__CFSocketSetFDForRead(CFSocketRef s
) {
1272 __CFReadSocketsTimeoutInvalid
= true;
1273 Boolean b
= __CFSocketFdSet(s
->_socket
, __CFReadSocketsFds
);
1274 if (b
&& INVALID_SOCKET
!= __CFWakeupSocketPair
[0]) {
1276 send(__CFWakeupSocketPair
[0], (const char *)&c
, sizeof(c
), 0);
1281 CF_INLINE Boolean
__CFSocketClearFDForRead(CFSocketRef s
) {
1282 __CFReadSocketsTimeoutInvalid
= true;
1283 Boolean b
= __CFSocketFdClr(s
->_socket
, __CFReadSocketsFds
);
1284 if (b
&& INVALID_SOCKET
!= __CFWakeupSocketPair
[0]) {
1286 send(__CFWakeupSocketPair
[0], (const char *)&c
, sizeof(c
), 0);
1291 CF_INLINE Boolean
__CFSocketSetFDForWrite(CFSocketRef s
) {
1292 // CFLog(5, CFSTR("__CFSocketSetFDForWrite(%p)"), s);
1293 Boolean b
= __CFSocketFdSet(s
->_socket
, __CFWriteSocketsFds
);
1294 if (b
&& INVALID_SOCKET
!= __CFWakeupSocketPair
[0]) {
1296 send(__CFWakeupSocketPair
[0], (const char *)&c
, sizeof(c
), 0);
1301 CF_INLINE Boolean
__CFSocketClearFDForWrite(CFSocketRef s
) {
1302 // CFLog(5, CFSTR("__CFSocketClearFDForWrite(%p)"), s);
1303 Boolean b
= __CFSocketFdClr(s
->_socket
, __CFWriteSocketsFds
);
1304 if (b
&& INVALID_SOCKET
!= __CFWakeupSocketPair
[0]) {
1306 send(__CFWakeupSocketPair
[0], (const char *)&c
, sizeof(c
), 0);
1311 #if DEPLOYMENT_TARGET_WINDOWS
1312 static Boolean WinSockUsed
= FALSE
;
1314 static void __CFSocketInitializeWinSock_Guts(void) {
1317 WORD versionRequested
= MAKEWORD(2, 2);
1319 int errorStatus
= WSAStartup(versionRequested
, &wsaData
);
1320 if (errorStatus
!= 0 || LOBYTE(wsaData
.wVersion
) != LOBYTE(versionRequested
) || HIBYTE(wsaData
.wVersion
) != HIBYTE(versionRequested
)) {
1322 CFLog(kCFLogLevelWarning
, CFSTR("*** Could not initialize WinSock subsystem!!!"));
1327 CF_EXPORT
void __CFSocketInitializeWinSock(void) {
1328 __CFSpinLock(&__CFActiveSocketsLock
);
1329 __CFSocketInitializeWinSock_Guts();
1330 __CFSpinUnlock(&__CFActiveSocketsLock
);
1333 CF_PRIVATE
void __CFSocketCleanup(void) {
1334 if (INVALID_SOCKET
!= __CFWakeupSocketPair
[0]) {
1335 closesocket(__CFWakeupSocketPair
[0]);
1336 __CFWakeupSocketPair
[0] = INVALID_SOCKET
;
1338 if (INVALID_SOCKET
!= __CFWakeupSocketPair
[1]) {
1339 closesocket(__CFWakeupSocketPair
[1]);
1340 __CFWakeupSocketPair
[1] = INVALID_SOCKET
;
1343 // technically this is not supposed to be called here since it will be called from dllmain, but I don't know where else to put it
1350 // CFNetwork needs to call this, especially for Win32 to get WSAStartup
1351 static void __CFSocketInitializeSockets(void) {
1352 __CFWriteSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
);
1353 __CFReadSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
);
1354 __CFWriteSocketsFds
= CFDataCreateMutable(kCFAllocatorSystemDefault
, 0);
1355 __CFReadSocketsFds
= CFDataCreateMutable(kCFAllocatorSystemDefault
, 0);
1356 zeroLengthData
= CFDataCreateMutable(kCFAllocatorSystemDefault
, 0);
1357 #if DEPLOYMENT_TARGET_WINDOWS
1358 __CFSocketInitializeWinSock_Guts();
1360 if (0 > __CFSocketCreateWakeupSocketPair()) {
1361 CFLog(kCFLogLevelWarning
, CFSTR("*** Could not create wakeup socket pair for CFSocket!!!"));
1364 /* wakeup sockets must be non-blocking */
1365 ioctlsocket(__CFWakeupSocketPair
[0], FIONBIO
, (u_long
*)&yes
);
1366 ioctlsocket(__CFWakeupSocketPair
[1], FIONBIO
, (u_long
*)&yes
);
1367 __CFSocketFdSet(__CFWakeupSocketPair
[1], __CFReadSocketsFds
);
1371 static CFRunLoopRef
__CFSocketCopyRunLoopToWakeUp(CFRunLoopSourceRef src
, CFMutableArrayRef runLoops
) {
1372 if (!src
) return NULL
;
1373 CFRunLoopRef rl
= NULL
;
1374 SInt32 idx
, cnt
= CFArrayGetCount(runLoops
);
1376 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(runLoops
, 0);
1377 for (idx
= 1; NULL
!= rl
&& idx
< cnt
; idx
++) {
1378 CFRunLoopRef value
= (CFRunLoopRef
)CFArrayGetValueAtIndex(runLoops
, idx
);
1379 if (value
!= rl
) rl
= NULL
;
1381 if (NULL
== rl
) { /* more than one different rl, so we must pick one */
1382 /* ideally, this would be a run loop which isn't also in a
1383 * signaled state for this or another source, but that's tricky;
1384 * we pick one that is running in an appropriate mode for this
1385 * source, and from those if possible one that is waiting; then
1386 * we move this run loop to the end of the list to scramble them
1387 * a bit, and always search from the front */
1388 Boolean foundIt
= false, foundBackup
= false;
1389 SInt32 foundIdx
= 0;
1390 for (idx
= 0; !foundIt
&& idx
< cnt
; idx
++) {
1391 CFRunLoopRef value
= (CFRunLoopRef
)CFArrayGetValueAtIndex(runLoops
, idx
);
1392 CFStringRef currentMode
= CFRunLoopCopyCurrentMode(value
);
1393 if (NULL
!= currentMode
) {
1394 if (CFRunLoopContainsSource(value
, src
, currentMode
)) {
1395 if (CFRunLoopIsWaiting(value
)) {
1398 } else if (!foundBackup
) {
1403 CFRelease(currentMode
);
1406 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(runLoops
, foundIdx
);
1408 CFArrayRemoveValueAtIndex(runLoops
, foundIdx
);
1409 CFArrayAppendValue(runLoops
, rl
);
1417 // If callBackNow, we immediately do client callbacks, else we have to signal a v0 RunLoopSource so the
1418 // callbacks can happen in another thread.
1419 static void __CFSocketHandleWrite(CFSocketRef s
, Boolean callBackNow
) {
1420 SInt32 errorCode
= 0;
1421 int errorSize
= sizeof(errorCode
);
1422 CFOptionFlags writeCallBacksAvailable
;
1424 if (!CFSocketIsValid(s
)) return;
1425 if (0 != (s
->_f
.client
& kCFSocketLeaveErrors
) || 0 != getsockopt(s
->_socket
, SOL_SOCKET
, SO_ERROR
, (char *)&errorCode
, (socklen_t
*)&errorSize
)) errorCode
= 0;
1426 // cast for WinSock bad API
1427 #if defined(LOG_CFSOCKET)
1428 if (errorCode
) fprintf(stdout
, "error %ld on socket %d\n", (long)errorCode
, s
->_socket
);
1431 writeCallBacksAvailable
= __CFSocketCallBackTypes(s
) & (kCFSocketWriteCallBack
| kCFSocketConnectCallBack
);
1432 if ((s
->_f
.client
& kCFSocketConnectCallBack
) != 0) writeCallBacksAvailable
&= ~kCFSocketConnectCallBack
;
1433 if (!__CFSocketIsValid(s
) || ((s
->_f
.disabled
& writeCallBacksAvailable
) == writeCallBacksAvailable
)) {
1434 __CFSocketUnlock(s
);
1437 s
->_errorCode
= errorCode
;
1438 __CFSocketSetWriteSignalled(s
);
1439 // CFLog(5, CFSTR("__CFSocketHandleWrite() signalling write on socket %p"), s);
1440 #if defined(LOG_CFSOCKET)
1441 fprintf(stdout
, "write signaling source for socket %d\n", s
->_socket
);
1444 __CFSocketDoCallback(s
, NULL
, NULL
, 0);
1446 CFRunLoopSourceSignal(s
->_source0
);
1447 CFMutableArrayRef runLoopsOrig
= (CFMutableArrayRef
)CFRetain(s
->_runLoops
);
1448 CFMutableArrayRef runLoopsCopy
= CFArrayCreateMutableCopy(kCFAllocatorSystemDefault
, 0, s
->_runLoops
);
1449 CFRunLoopSourceRef source0
= s
->_source0
;
1450 if (NULL
!= source0
&& !CFRunLoopSourceIsValid(source0
)) {
1453 if (source0
) CFRetain(source0
);
1454 __CFSocketUnlock(s
);
1455 CFRunLoopRef rl
= __CFSocketCopyRunLoopToWakeUp(source0
, runLoopsCopy
);
1456 if (source0
) CFRelease(source0
);
1458 CFRunLoopWakeUp(rl
);
1462 if (runLoopsOrig
== s
->_runLoops
) {
1463 s
->_runLoops
= runLoopsCopy
;
1464 runLoopsCopy
= NULL
;
1465 CFRelease(runLoopsOrig
);
1467 __CFSocketUnlock(s
);
1468 CFRelease(runLoopsOrig
);
1469 if (runLoopsCopy
) CFRelease(runLoopsCopy
);
1473 static void __CFSocketHandleRead(CFSocketRef s
, Boolean causedByTimeout
)
1475 CFDataRef data
= NULL
, address
= NULL
;
1476 CFSocketNativeHandle sock
= INVALID_SOCKET
;
1477 if (!CFSocketIsValid(s
)) return;
1478 if (__CFSocketReadCallBackType(s
) == kCFSocketDataCallBack
) {
1479 uint8_t bufferArray
[MAX_CONNECTION_ORIENTED_DATA_SIZE
], *buffer
;
1480 uint8_t name
[MAX_SOCKADDR_LEN
];
1481 int namelen
= sizeof(name
);
1483 if (__CFSocketIsConnectionOriented(s
)) {
1484 buffer
= bufferArray
;
1485 recvlen
= recvfrom(s
->_socket
, (char *)buffer
, MAX_CONNECTION_ORIENTED_DATA_SIZE
, 0, (struct sockaddr
*)name
, (socklen_t
*)&namelen
);
1487 buffer
= (uint8_t *)malloc(MAX_DATA_SIZE
);
1488 if (buffer
) recvlen
= recvfrom(s
->_socket
, (char *)buffer
, MAX_DATA_SIZE
, 0, (struct sockaddr
*)name
, (socklen_t
*)&namelen
);
1490 #if defined(LOG_CFSOCKET)
1491 fprintf(stdout
, "read %ld bytes on socket %d\n", (long)recvlen
, s
->_socket
);
1494 //??? should return error if <0
1495 /* zero-length data is the signal for perform to invalidate */
1496 data
= (CFDataRef
)CFRetain(zeroLengthData
);
1498 data
= CFDataCreate(CFGetAllocator(s
), buffer
, recvlen
);
1500 if (buffer
&& buffer
!= bufferArray
) free(buffer
);
1502 if (!__CFSocketIsValid(s
)) {
1504 __CFSocketUnlock(s
);
1507 __CFSocketSetReadSignalled(s
);
1508 if (NULL
!= name
&& 0 < namelen
) {
1509 //??? possible optimizations: uniquing; storing last value
1510 address
= CFDataCreate(CFGetAllocator(s
), name
, namelen
);
1511 } else if (__CFSocketIsConnectionOriented(s
)) {
1512 if (NULL
== s
->_peerAddress
) __CFSocketEstablishPeerAddress(s
);
1513 if (NULL
!= s
->_peerAddress
) address
= (CFDataRef
)CFRetain(s
->_peerAddress
);
1515 if (NULL
== address
) {
1516 address
= (CFDataRef
)CFRetain(zeroLengthData
);
1518 if (NULL
== s
->_dataQueue
) {
1519 s
->_dataQueue
= CFArrayCreateMutable(CFGetAllocator(s
), 0, &kCFTypeArrayCallBacks
);
1521 if (NULL
== s
->_addressQueue
) {
1522 s
->_addressQueue
= CFArrayCreateMutable(CFGetAllocator(s
), 0, &kCFTypeArrayCallBacks
);
1524 CFArrayAppendValue(s
->_dataQueue
, data
);
1526 CFArrayAppendValue(s
->_addressQueue
, address
);
1529 && (s
->_f
.client
& kCFSocketDataCallBack
) != 0 && (s
->_f
.disabled
& kCFSocketDataCallBack
) == 0
1530 && __CFSocketIsScheduled(s
)
1532 __CFSpinLock(&__CFActiveSocketsLock
);
1533 /* restore socket to fds */
1534 __CFSocketSetFDForRead(s
);
1535 __CFSpinUnlock(&__CFActiveSocketsLock
);
1537 } else if (__CFSocketReadCallBackType(s
) == kCFSocketAcceptCallBack
) {
1538 uint8_t name
[MAX_SOCKADDR_LEN
];
1539 int namelen
= sizeof(name
);
1540 sock
= accept(s
->_socket
, (struct sockaddr
*)name
, (socklen_t
*)&namelen
);
1541 if (INVALID_SOCKET
== sock
) {
1542 //??? should return error
1545 if (NULL
!= name
&& 0 < namelen
) {
1546 address
= CFDataCreate(CFGetAllocator(s
), name
, namelen
);
1548 address
= (CFDataRef
)CFRetain(zeroLengthData
);
1551 if (!__CFSocketIsValid(s
)) {
1554 __CFSocketUnlock(s
);
1557 __CFSocketSetReadSignalled(s
);
1558 if (NULL
== s
->_dataQueue
) {
1559 s
->_dataQueue
= CFArrayCreateMutable(CFGetAllocator(s
), 0, NULL
);
1561 if (NULL
== s
->_addressQueue
) {
1562 s
->_addressQueue
= CFArrayCreateMutable(CFGetAllocator(s
), 0, &kCFTypeArrayCallBacks
);
1564 CFArrayAppendValue(s
->_dataQueue
, (void *)(uintptr_t)sock
);
1565 CFArrayAppendValue(s
->_addressQueue
, address
);
1567 if ((s
->_f
.client
& kCFSocketAcceptCallBack
) != 0 && (s
->_f
.disabled
& kCFSocketAcceptCallBack
) == 0
1568 && __CFSocketIsScheduled(s
)
1570 __CFSpinLock(&__CFActiveSocketsLock
);
1571 /* restore socket to fds */
1572 __CFSocketSetFDForRead(s
);
1573 __CFSpinUnlock(&__CFActiveSocketsLock
);
1577 if (!__CFSocketIsValid(s
) || (s
->_f
.disabled
& kCFSocketReadCallBack
) != 0) {
1578 __CFSocketUnlock(s
);
1582 if (causedByTimeout
) {
1583 #if defined(LOG_CFSOCKET)
1584 fprintf(stdout
, "TIMEOUT RECEIVED - WILL SIGNAL IMMEDIATELY TO FLUSH (%ld buffered)\n", s
->_bytesToBufferPos
);
1586 /* we've got a timeout, but no bytes read, and we don't have any bytes to send. Ignore the timeout. */
1587 if (s
->_bytesToBufferPos
== 0 && s
->_leftoverBytes
== NULL
) {
1588 #if defined(LOG_CFSOCKET)
1589 fprintf(stdout
, "TIMEOUT - but no bytes, restoring to active set\n");
1593 __CFSpinLock(&__CFActiveSocketsLock
);
1594 /* restore socket to fds */
1595 __CFSocketSetFDForRead(s
);
1596 __CFSpinUnlock(&__CFActiveSocketsLock
);
1597 __CFSocketUnlock(s
);
1600 } else if (s
->_bytesToBuffer
!= 0 && ! s
->_atEOF
) {
1603 CFIndex ctRemaining
= s
->_bytesToBuffer
- s
->_bytesToBufferPos
;
1605 /* if our buffer has room, we go ahead and buffer */
1606 if (ctRemaining
> 0) {
1607 base
= CFDataGetMutableBytePtr(s
->_readBuffer
);
1610 ctRead
= read(CFSocketGetNative(s
), &base
[s
->_bytesToBufferPos
], ctRemaining
);
1611 } while (ctRead
== -1 && errno
== EAGAIN
);
1615 s
->_bufferedReadError
= errno
;
1617 #if defined(LOG_CFSOCKET)
1618 fprintf(stderr
, "BUFFERED READ GOT ERROR %d\n", errno
);
1623 #if defined(LOG_CFSOCKET)
1624 fprintf(stdout
, "DONE READING (EOF) - GOING TO SIGNAL\n");
1630 s
->_bytesToBufferPos
+= ctRead
;
1631 if (s
->_bytesToBuffer
!= s
->_bytesToBufferPos
) {
1632 #if defined(LOG_CFSOCKET)
1633 fprintf(stdout
, "READ %ld - need %ld MORE - GOING BACK FOR MORE\n", ctRead
, s
->_bytesToBuffer
- s
->_bytesToBufferPos
);
1635 __CFSpinLock(&__CFActiveSocketsLock
);
1636 /* restore socket to fds */
1637 __CFSocketSetFDForRead(s
);
1638 __CFSpinUnlock(&__CFActiveSocketsLock
);
1639 __CFSocketUnlock(s
);
1642 #if defined(LOG_CFSOCKET)
1643 fprintf(stdout
, "DONE READING (read %ld bytes) - GOING TO SIGNAL\n", ctRead
);
1650 __CFSocketSetReadSignalled(s
);
1652 #if defined(LOG_CFSOCKET)
1653 fprintf(stdout
, "read signaling source for socket %d\n", s
->_socket
);
1655 CFRunLoopSourceSignal(s
->_source0
);
1656 CFMutableArrayRef runLoopsOrig
= (CFMutableArrayRef
)CFRetain(s
->_runLoops
);
1657 CFMutableArrayRef runLoopsCopy
= CFArrayCreateMutableCopy(kCFAllocatorSystemDefault
, 0, s
->_runLoops
);
1658 CFRunLoopSourceRef source0
= s
->_source0
;
1659 if (NULL
!= source0
&& !CFRunLoopSourceIsValid(source0
)) {
1662 if (source0
) CFRetain(source0
);
1663 __CFSocketUnlock(s
);
1664 CFRunLoopRef rl
= __CFSocketCopyRunLoopToWakeUp(source0
, runLoopsCopy
);
1665 if (source0
) CFRelease(source0
);
1667 CFRunLoopWakeUp(rl
);
1671 if (runLoopsOrig
== s
->_runLoops
) {
1672 s
->_runLoops
= runLoopsCopy
;
1673 runLoopsCopy
= NULL
;
1674 CFRelease(runLoopsOrig
);
1676 __CFSocketUnlock(s
);
1677 CFRelease(runLoopsOrig
);
1678 if (runLoopsCopy
) CFRelease(runLoopsCopy
);
1681 static struct timeval
* intervalToTimeval(CFTimeInterval timeout
, struct timeval
* tv
)
1686 tv
->tv_sec
= (0 >= timeout
|| INT_MAX
<= timeout
) ? INT_MAX
: (int)(float)floor(timeout
);
1687 tv
->tv_usec
= (int)((timeout
- floor(timeout
)) * 1.0E6
);
1692 /* note that this returns a pointer to the min value, which won't have changed during
1693 the dictionary apply, since we've got the active sockets lock held */
1694 static void _calcMinTimeout_locked(const void* val
, void* ctxt
)
1696 CFSocketRef s
= (CFSocketRef
) val
;
1697 struct timeval
** minTime
= (struct timeval
**) ctxt
;
1698 if (timerisset(&s
->_readBufferTimeout
) && (*minTime
== NULL
|| timercmp(&s
->_readBufferTimeout
, *minTime
, <)))
1699 *minTime
= &s
->_readBufferTimeout
;
1700 else if (s
->_leftoverBytes
) {
1701 /* If there's anyone with leftover bytes, they'll need to be awoken immediately */
1702 static struct timeval sKickerTime
= { 0, 0 };
1703 *minTime
= &sKickerTime
;
1707 void __CFSocketSetSocketReadBufferAttrs(CFSocketRef s
, CFTimeInterval timeout
, CFIndex length
)
1709 struct timeval timeoutVal
;
1711 intervalToTimeval(timeout
, &timeoutVal
);
1713 /* lock ordering is socket lock, activesocketslock */
1714 /* activesocketslock protects our timeout calculation */
1716 __CFSpinLock(&__CFActiveSocketsLock
);
1718 if (s
->_bytesToBuffer
!= length
) {
1719 CFIndex ctBuffer
= s
->_bytesToBufferPos
- s
->_bytesToBufferReadPos
;
1722 /* As originally envisaged, you were supposed to be sure to drain the buffer before
1723 * issuing another request on the socket. In practice, there seem to be times when we want to re-use
1724 * the stream (or perhaps, are on our way to closing it out) and this policy doesn't work so well.
1725 * So, if someone changes the buffer size while we have bytes already buffered, we put them
1726 * aside and use them to satisfy any subsequent reads.
1728 #if defined(LOG_CFSOCKET)
1729 fprintf(stdout
, "%s(%d): WARNING: shouldn't set read buffer length while data (%ld bytes) is still in the read buffer (leftover total %ld)", __FUNCTION__
, __LINE__
, ctBuffer
, s
->_leftoverBytes
? CFDataGetLength(s
->_leftoverBytes
) : 0);
1732 if (s
->_leftoverBytes
== NULL
)
1733 s
->_leftoverBytes
= CFDataCreateMutable(CFGetAllocator(s
), 0);
1735 /* append the current buffered bytes over. We'll keep draining _leftoverBytes while we have them... */
1736 CFDataAppendBytes(s
->_leftoverBytes
, CFDataGetBytePtr(s
->_readBuffer
) + s
->_bytesToBufferReadPos
, ctBuffer
);
1737 CFRelease(s
->_readBuffer
);
1738 s
->_readBuffer
= NULL
;
1740 s
->_bytesToBuffer
= 0;
1741 s
->_bytesToBufferPos
= 0;
1742 s
->_bytesToBufferReadPos
= 0;
1745 s
->_bytesToBuffer
= 0;
1746 s
->_bytesToBufferPos
= 0;
1747 s
->_bytesToBufferReadPos
= 0;
1748 if (s
->_readBuffer
) {
1749 CFRelease(s
->_readBuffer
);
1750 s
->_readBuffer
= NULL
;
1752 // Zero length buffer, smash the timeout
1753 timeoutVal
.tv_sec
= 0;
1754 timeoutVal
.tv_usec
= 0;
1756 /* if the buffer shrank, we can re-use the old one */
1757 if (length
> s
->_bytesToBuffer
) {
1758 if (s
->_readBuffer
) {
1759 CFRelease(s
->_readBuffer
);
1760 s
->_readBuffer
= NULL
;
1764 s
->_bytesToBuffer
= length
;
1765 s
->_bytesToBufferPos
= 0;
1766 s
->_bytesToBufferReadPos
= 0;
1767 if (s
->_readBuffer
== NULL
) {
1768 s
->_readBuffer
= CFDataCreateMutable(kCFAllocatorSystemDefault
, length
);
1769 CFDataSetLength(s
->_readBuffer
, length
);
1774 if (timercmp(&s
->_readBufferTimeout
, &timeoutVal
, !=)) {
1775 s
->_readBufferTimeout
= timeoutVal
;
1776 __CFReadSocketsTimeoutInvalid
= true;
1779 __CFSpinUnlock(&__CFActiveSocketsLock
);
1780 __CFSocketUnlock(s
);
1783 CFIndex
__CFSocketRead(CFSocketRef s
, UInt8
* buffer
, CFIndex length
, int* error
)
1785 #if defined(LOG_CFSOCKET)
1786 fprintf(stdout
, "READING BYTES FOR SOCKET %d (%ld buffered, out of %ld desired, eof = %d, err = %d)\n", s
->_socket
, s
->_bytesToBufferPos
, s
->_bytesToBuffer
, s
->_atEOF
, s
->_bufferedReadError
);
1789 CFIndex result
= -1;
1795 /* Any leftover buffered bytes? */
1796 if (s
->_leftoverBytes
) {
1797 CFIndex ctBuffer
= CFDataGetLength(s
->_leftoverBytes
);
1799 fprintf(stderr
, "%s(%ld): WARNING: Draining %ld leftover bytes first\n\n", __FUNCTION__
, (long)__LINE__
, (long)ctBuffer
);
1801 if (ctBuffer
> length
)
1803 memcpy(buffer
, CFDataGetBytePtr(s
->_leftoverBytes
), ctBuffer
);
1804 if (ctBuffer
< CFDataGetLength(s
->_leftoverBytes
))
1805 CFDataReplaceBytes(s
->_leftoverBytes
, CFRangeMake(0, ctBuffer
), NULL
, 0);
1807 CFRelease(s
->_leftoverBytes
);
1808 s
->_leftoverBytes
= NULL
;
1814 /* return whatever we've buffered */
1815 if (s
->_bytesToBuffer
!= 0) {
1816 CFIndex ctBuffer
= s
->_bytesToBufferPos
- s
->_bytesToBufferReadPos
;
1818 /* drain our buffer first */
1819 if (ctBuffer
> length
)
1821 memcpy(buffer
, CFDataGetBytePtr(s
->_readBuffer
) + s
->_bytesToBufferReadPos
, ctBuffer
);
1822 s
->_bytesToBufferReadPos
+= ctBuffer
;
1823 if (s
->_bytesToBufferReadPos
== s
->_bytesToBufferPos
) {
1824 #if defined(LOG_CFSOCKET)
1825 fprintf(stdout
, "DRAINED BUFFER - SHOULD START BUFFERING AGAIN!\n");
1827 s
->_bytesToBufferPos
= 0;
1828 s
->_bytesToBufferReadPos
= 0;
1831 #if defined(LOG_CFSOCKET)
1832 fprintf(stdout
, "SLURPED %ld BYTES FROM BUFFER %ld LEFT TO READ!\n", ctBuffer
, length
);
1839 /* nothing buffered, or no buffer selected */
1841 /* Did we get an error on a previous read (or buffered read)? */
1842 if (s
->_bufferedReadError
!= 0) {
1843 #if defined(LOG_CFSOCKET)
1844 fprintf(stdout
, "RETURNING ERROR %d\n", s
->_bufferedReadError
);
1846 *error
= s
->_bufferedReadError
;
1851 /* nothing buffered, if we've hit eof, don't bother reading any more */
1853 #if defined(LOG_CFSOCKET)
1854 fprintf(stdout
, "RETURNING EOF\n");
1861 result
= read(CFSocketGetNative(s
), buffer
, length
);
1862 #if defined(LOG_CFSOCKET)
1863 fprintf(stdout
, "READ %ld bytes", result
);
1867 /* note that we hit EOF */
1869 } else if (result
< 0) {
1872 /* if it wasn't EAGAIN, record it (although we shouldn't get called again) */
1873 if (*error
!= EAGAIN
) {
1874 s
->_bufferedReadError
= *error
;
1879 __CFSocketUnlock(s
);
1884 Boolean
__CFSocketGetBytesAvailable(CFSocketRef s
, CFIndex
* ctBytesAvailable
)
1886 CFIndex ctBuffer
= s
->_bytesToBufferPos
- s
->_bytesToBufferReadPos
;
1887 if (ctBuffer
!= 0) {
1888 *ctBytesAvailable
= ctBuffer
;
1892 unsigned long bytesAvailable
;
1893 result
= ioctlsocket(CFSocketGetNative(s
), FIONREAD
, &bytesAvailable
);
1896 *ctBytesAvailable
= (CFIndex
) bytesAvailable
;
1901 #if defined(LOG_CFSOCKET)
1902 static void __CFSocketWriteSocketList(CFArrayRef sockets
, CFDataRef fdSet
, Boolean onlyIfSet
) {
1903 fd_set
*tempfds
= (fd_set
*)CFDataGetBytePtr(fdSet
);
1905 for (idx
= 0, cnt
= CFArrayGetCount(sockets
); idx
< cnt
; idx
++) {
1906 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(sockets
, idx
);
1907 if (FD_ISSET(s
->_socket
, tempfds
)) {
1908 fprintf(stdout
, "%d ", s
->_socket
);
1909 } else if (!onlyIfSet
) {
1910 fprintf(stdout
, "(%d) ", s
->_socket
);
1917 clearInvalidFileDescriptors(CFMutableDataRef d
)
1920 SInt32 count
= __CFSocketFdGetSize(d
);
1921 fd_set
* s
= (fd_set
*) CFDataGetMutableBytePtr(d
);
1922 for (SInt32 idx
= 0; idx
< count
; idx
++) {
1923 if (FD_ISSET(idx
, s
))
1924 if (! __CFNativeSocketIsValid(idx
)) {
1934 SInt32 selectError
= __CFSocketLastError();
1935 #if defined(LOG_CFSOCKET)
1936 fprintf(stdout
, "socket manager received error %ld from select\n", (long)selectError
);
1938 if (EBADF
== selectError
) {
1939 CFMutableArrayRef invalidSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
1941 __CFSpinLock(&__CFActiveSocketsLock
);
1942 CFIndex cnt
= CFArrayGetCount(__CFWriteSockets
);
1944 for (idx
= 0; idx
< cnt
; idx
++) {
1945 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFWriteSockets
, idx
);
1946 if (!__CFNativeSocketIsValid(s
->_socket
)) {
1947 #if defined(LOG_CFSOCKET)
1948 fprintf(stdout
, "socket manager found write socket %d invalid\n", s
->_socket
);
1950 CFArrayAppendValue(invalidSockets
, s
);
1953 cnt
= CFArrayGetCount(__CFReadSockets
);
1954 for (idx
= 0; idx
< cnt
; idx
++) {
1955 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFReadSockets
, idx
);
1956 if (!__CFNativeSocketIsValid(s
->_socket
)) {
1957 #if defined(LOG_CFSOCKET)
1958 fprintf(stdout
, "socket manager found read socket %d invalid\n", s
->_socket
);
1960 CFArrayAppendValue(invalidSockets
, s
);
1965 cnt
= CFArrayGetCount(invalidSockets
);
1967 /* Note that we're doing this only when we got EBADF but otherwise
1968 * don't have an explicit bad descriptor. Note that the lock is held now.
1969 * Finally, note that cnt == 0 doesn't necessarily mean
1970 * that this loop will do anything, since fd's may have been invalidated
1971 * while we were in select.
1974 #if defined(LOG_CFSOCKET)
1975 fprintf(stdout
, "socket manager received EBADF(1): No sockets were marked as invalid, cleaning out fdsets\n");
1978 clearInvalidFileDescriptors(__CFReadSocketsFds
);
1979 clearInvalidFileDescriptors(__CFWriteSocketsFds
);
1982 __CFSpinUnlock(&__CFActiveSocketsLock
);
1984 for (idx
= 0; idx
< cnt
; idx
++) {
1985 CFSocketInvalidate(((CFSocketRef
)CFArrayGetValueAtIndex(invalidSockets
, idx
)));
1987 CFRelease(invalidSockets
);
1992 __attribute__ ((noreturn
)) // mostly interesting for shutting up a warning
1993 #endif /* __GNUC__ */
1994 static void __CFSocketManager(void * arg
)
1996 pthread_setname_np("com.apple.CFSocket.private");
1997 if (objc_collectingEnabled()) objc_registerThreadWithCollector();
1998 SInt32 nrfds
, maxnrfds
, fdentries
= 1;
2000 fd_set
*exceptfds
= NULL
;
2001 fd_set
*writefds
= (fd_set
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, fdentries
* sizeof(fd_mask
), 0);
2002 fd_set
*readfds
= (fd_set
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, fdentries
* sizeof(fd_mask
), 0);
2005 uint8_t buffer
[256];
2006 CFMutableArrayRef selectedWriteSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
2007 CFMutableArrayRef selectedReadSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
2008 CFIndex selectedWriteSocketsIndex
= 0, selectedReadSocketsIndex
= 0;
2011 struct timeval
* pTimeout
= NULL
;
2012 struct timeval timeBeforeSelect
;
2015 __CFSpinLock(&__CFActiveSocketsLock
);
2016 __CFSocketManagerIteration
++;
2017 #if defined(LOG_CFSOCKET)
2018 fprintf(stdout
, "socket manager iteration %lu looking at read sockets ", (unsigned long)__CFSocketManagerIteration
);
2019 __CFSocketWriteSocketList(__CFReadSockets
, __CFReadSocketsFds
, FALSE
);
2020 if (0 < CFArrayGetCount(__CFWriteSockets
)) {
2021 fprintf(stdout
, " and write sockets ");
2022 __CFSocketWriteSocketList(__CFWriteSockets
, __CFWriteSocketsFds
, FALSE
);
2024 fprintf(stdout
, "\n");
2026 rfds
= __CFSocketFdGetSize(__CFReadSocketsFds
);
2027 wfds
= __CFSocketFdGetSize(__CFWriteSocketsFds
);
2028 maxnrfds
= __CFMax(rfds
, wfds
);
2029 if (maxnrfds
> fdentries
* (int)NFDBITS
) {
2030 fdentries
= (maxnrfds
+ NFDBITS
- 1) / NFDBITS
;
2031 writefds
= (fd_set
*)CFAllocatorReallocate(kCFAllocatorSystemDefault
, writefds
, fdentries
* sizeof(fd_mask
), 0);
2032 readfds
= (fd_set
*)CFAllocatorReallocate(kCFAllocatorSystemDefault
, readfds
, fdentries
* sizeof(fd_mask
), 0);
2034 memset(writefds
, 0, fdentries
* sizeof(fd_mask
));
2035 memset(readfds
, 0, fdentries
* sizeof(fd_mask
));
2036 CFDataGetBytes(__CFWriteSocketsFds
, CFRangeMake(0, CFDataGetLength(__CFWriteSocketsFds
)), (UInt8
*)writefds
);
2037 CFDataGetBytes(__CFReadSocketsFds
, CFRangeMake(0, CFDataGetLength(__CFReadSocketsFds
)), (UInt8
*)readfds
);
2039 if (__CFReadSocketsTimeoutInvalid
) {
2040 struct timeval
* minTimeout
= NULL
;
2041 __CFReadSocketsTimeoutInvalid
= false;
2042 #if defined(LOG_CFSOCKET)
2043 fprintf(stdout
, "Figuring out which sockets have timeouts...\n");
2045 CFArrayApplyFunction(__CFReadSockets
, CFRangeMake(0, CFArrayGetCount(__CFReadSockets
)), _calcMinTimeout_locked
, (void*) &minTimeout
);
2047 if (minTimeout
== NULL
) {
2048 #if defined(LOG_CFSOCKET)
2049 fprintf(stdout
, "No one wants a timeout!\n");
2053 #if defined(LOG_CFSOCKET)
2054 fprintf(stdout
, "timeout will be %ld, %d!\n", minTimeout
->tv_sec
, minTimeout
->tv_usec
);
2062 #if defined(LOG_CFSOCKET)
2063 fprintf(stdout
, "select will have a %ld, %d timeout\n", pTimeout
->tv_sec
, pTimeout
->tv_usec
);
2065 gettimeofday(&timeBeforeSelect
, NULL
);
2068 __CFSpinUnlock(&__CFActiveSocketsLock
);
2070 #if DEPLOYMENT_TARGET_WINDOWS
2071 // On Windows, select checks connection failed sockets via the exceptfds parameter. connection succeeded is checked via writefds. We need both.
2072 exceptfds
= writefds
;
2074 nrfds
= select(maxnrfds
, readfds
, writefds
, exceptfds
, pTimeout
);
2076 #if defined(LOG_CFSOCKET)
2077 fprintf(stdout
, "socket manager woke from select, ret=%ld\n", (long)nrfds
);
2081 * select returned a timeout
2084 struct timeval timeAfterSelect
;
2085 struct timeval deltaTime
;
2086 gettimeofday(&timeAfterSelect
, NULL
);
2087 /* timeBeforeSelect becomes the delta */
2088 timersub(&timeAfterSelect
, &timeBeforeSelect
, &deltaTime
);
2090 #if defined(LOG_CFSOCKET)
2091 fprintf(stdout
, "Socket manager received timeout - kicking off expired reads (expired delta %ld, %d)\n", deltaTime
.tv_sec
, deltaTime
.tv_usec
);
2094 __CFSpinLock(&__CFActiveSocketsLock
);
2097 cnt
= CFArrayGetCount(__CFReadSockets
);
2098 for (idx
= 0; idx
< cnt
; idx
++) {
2099 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFReadSockets
, idx
);
2100 if (timerisset(&s
->_readBufferTimeout
) || s
->_leftoverBytes
) {
2101 CFSocketNativeHandle sock
= s
->_socket
;
2102 // We might have an new element in __CFReadSockets that we weren't listening to,
2103 // in which case we must be sure not to test a bit in the fdset that is
2104 // outside our mask size.
2105 Boolean sockInBounds
= (0 <= sock
&& sock
< maxnrfds
);
2106 /* if this sockets timeout is less than or equal elapsed time, then signal it */
2107 if (INVALID_SOCKET
!= sock
&& sockInBounds
) {
2108 #if defined(LOG_CFSOCKET)
2109 fprintf(stdout
, "Expiring socket %d (delta %ld, %d)\n", sock
, s
->_readBufferTimeout
.tv_sec
, s
->_readBufferTimeout
.tv_usec
);
2111 CFArraySetValueAtIndex(selectedReadSockets
, selectedReadSocketsIndex
, s
);
2112 selectedReadSocketsIndex
++;
2113 /* socket is removed from fds here, will be restored in read handling or in perform function */
2114 if (!tempfds
) tempfds
= (fd_set
*)CFDataGetMutableBytePtr(__CFReadSocketsFds
);
2115 FD_CLR(sock
, tempfds
);
2120 __CFSpinUnlock(&__CFActiveSocketsLock
);
2122 /* and below, we dispatch through the normal read dispatch mechanism */
2126 manageSelectError();
2129 if (FD_ISSET(__CFWakeupSocketPair
[1], readfds
)) {
2130 recv(__CFWakeupSocketPair
[1], (char *)buffer
, sizeof(buffer
), 0);
2131 #if defined(LOG_CFSOCKET)
2132 fprintf(stdout
, "socket manager received %c on wakeup socket\n", buffer
[0]);
2135 __CFSpinLock(&__CFActiveSocketsLock
);
2137 cnt
= CFArrayGetCount(__CFWriteSockets
);
2138 for (idx
= 0; idx
< cnt
; idx
++) {
2139 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFWriteSockets
, idx
);
2140 CFSocketNativeHandle sock
= s
->_socket
;
2141 // We might have an new element in __CFWriteSockets that we weren't listening to,
2142 // in which case we must be sure not to test a bit in the fdset that is
2143 // outside our mask size.
2144 Boolean sockInBounds
= (0 <= sock
&& sock
< maxnrfds
);
2145 if (INVALID_SOCKET
!= sock
&& sockInBounds
) {
2146 if (FD_ISSET(sock
, writefds
)) {
2147 CFArraySetValueAtIndex(selectedWriteSockets
, selectedWriteSocketsIndex
, s
);
2148 selectedWriteSocketsIndex
++;
2149 /* socket is removed from fds here, restored by CFSocketReschedule */
2150 if (!tempfds
) tempfds
= (fd_set
*)CFDataGetMutableBytePtr(__CFWriteSocketsFds
);
2151 FD_CLR(sock
, tempfds
);
2152 // CFLog(5, CFSTR("Manager: cleared socket %p from write fds"), s);
2157 cnt
= CFArrayGetCount(__CFReadSockets
);
2158 for (idx
= 0; idx
< cnt
; idx
++) {
2159 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFReadSockets
, idx
);
2160 CFSocketNativeHandle sock
= s
->_socket
;
2161 // We might have an new element in __CFReadSockets that we weren't listening to,
2162 // in which case we must be sure not to test a bit in the fdset that is
2163 // outside our mask size.
2164 Boolean sockInBounds
= (0 <= sock
&& sock
< maxnrfds
);
2165 if (INVALID_SOCKET
!= sock
&& sockInBounds
&& FD_ISSET(sock
, readfds
)) {
2166 CFArraySetValueAtIndex(selectedReadSockets
, selectedReadSocketsIndex
, s
);
2167 selectedReadSocketsIndex
++;
2168 /* socket is removed from fds here, will be restored in read handling or in perform function */
2169 if (!tempfds
) tempfds
= (fd_set
*)CFDataGetMutableBytePtr(__CFReadSocketsFds
);
2170 FD_CLR(sock
, tempfds
);
2173 __CFSpinUnlock(&__CFActiveSocketsLock
);
2175 for (idx
= 0; idx
< selectedWriteSocketsIndex
; idx
++) {
2176 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(selectedWriteSockets
, idx
);
2177 if (kCFNull
== (CFNullRef
)s
) continue;
2178 #if defined(LOG_CFSOCKET)
2179 fprintf(stdout
, "socket manager signaling socket %d for write\n", s
->_socket
);
2181 __CFSocketHandleWrite(s
, FALSE
);
2182 CFArraySetValueAtIndex(selectedWriteSockets
, idx
, kCFNull
);
2184 selectedWriteSocketsIndex
= 0;
2186 for (idx
= 0; idx
< selectedReadSocketsIndex
; idx
++) {
2187 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(selectedReadSockets
, idx
);
2188 if (kCFNull
== (CFNullRef
)s
) continue;
2189 #if defined(LOG_CFSOCKET)
2190 fprintf(stdout
, "socket manager signaling socket %d for read\n", s
->_socket
);
2192 __CFSocketHandleRead(s
, nrfds
== 0);
2193 CFArraySetValueAtIndex(selectedReadSockets
, idx
, kCFNull
);
2195 selectedReadSocketsIndex
= 0;
2199 static CFStringRef
__CFSocketCopyDescription(CFTypeRef cf
) {
2200 CFSocketRef s
= (CFSocketRef
)cf
;
2201 CFMutableStringRef result
;
2202 CFStringRef contextDesc
= NULL
;
2203 void *contextInfo
= NULL
;
2204 CFStringRef (*contextCopyDescription
)(const void *info
) = NULL
;
2205 result
= CFStringCreateMutable(CFGetAllocator(s
), 0);
2207 void *addr
= s
->_callout
;
2208 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2210 const char *name
= (dladdr(addr
, &info
) && info
.dli_saddr
== addr
&& info
.dli_sname
) ? info
.dli_sname
: "???";
2212 // don't bother trying to figure out callout names
2213 const char *name
= "<unknown>";
2215 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"), (int)(s
->_socketType
), s
->_socket
, (long)s
->_socketSetCount
, __CFSocketCallBackTypes(s
), name
, addr
, s
->_source0
, s
->_runLoops
);
2216 contextInfo
= s
->_context
.info
;
2217 contextCopyDescription
= s
->_context
.copyDescription
;
2218 __CFSocketUnlock(s
);
2219 if (NULL
!= contextInfo
&& NULL
!= contextCopyDescription
) {
2220 contextDesc
= (CFStringRef
)contextCopyDescription(contextInfo
);
2222 if (NULL
== contextDesc
) {
2223 contextDesc
= CFStringCreateWithFormat(CFGetAllocator(s
), NULL
, CFSTR("<CFSocket context %p>"), contextInfo
);
2225 CFStringAppend(result
, contextDesc
);
2226 CFStringAppend(result
, CFSTR("}"));
2227 CFRelease(contextDesc
);
2231 static void __CFSocketDeallocate(CFTypeRef cf
) {
2232 /* Since CFSockets are cached, we can only get here sometime after being invalidated */
2233 CFSocketRef s
= (CFSocketRef
)cf
;
2234 if (NULL
!= s
->_address
) {
2235 CFRelease(s
->_address
);
2238 if (NULL
!= s
->_readBuffer
) {
2239 CFRelease(s
->_readBuffer
);
2240 s
->_readBuffer
= NULL
;
2242 if (NULL
!= s
->_leftoverBytes
) {
2243 CFRelease(s
->_leftoverBytes
);
2244 s
->_leftoverBytes
= NULL
;
2246 timerclear(&s
->_readBufferTimeout
);
2247 s
->_bytesToBuffer
= 0;
2248 s
->_bytesToBufferPos
= 0;
2249 s
->_bytesToBufferReadPos
= 0;
2251 s
->_bufferedReadError
= 0;
2254 static CFTypeID __kCFSocketTypeID
= _kCFRuntimeNotATypeID
;
2256 static const CFRuntimeClass __CFSocketClass
= {
2261 __CFSocketDeallocate
,
2265 __CFSocketCopyDescription
2268 CFTypeID
CFSocketGetTypeID(void) {
2269 if (_kCFRuntimeNotATypeID
== __kCFSocketTypeID
) {
2270 __kCFSocketTypeID
= _CFRuntimeRegisterClass(&__CFSocketClass
);
2271 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2273 int ret1
= getrlimit(RLIMIT_NOFILE
, &lim1
);
2274 int mib
[] = {CTL_KERN
, KERN_MAXFILESPERPROC
};
2276 size_t len
= sizeof(int);
2277 int ret0
= sysctl(mib
, 2, &maxfd
, &len
, NULL
, 0);
2278 if (0 == ret0
&& 0 == ret1
&& lim1
.rlim_max
< maxfd
) maxfd
= lim1
.rlim_max
;
2279 if (0 == ret1
&& lim1
.rlim_cur
< maxfd
) {
2280 struct rlimit lim2
= lim1
;
2281 lim2
.rlim_cur
+= 2304;
2282 if (maxfd
< lim2
.rlim_cur
) lim2
.rlim_cur
= maxfd
;
2283 setrlimit(RLIMIT_NOFILE
, &lim2
);
2284 // we try, but do not go to extraordinary measures
2288 return __kCFSocketTypeID
;
2291 static CFSocketRef
_CFSocketCreateWithNative(CFAllocatorRef allocator
, CFSocketNativeHandle sock
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
, Boolean useExistingInstance
) {
2294 int typeSize
= sizeof(memory
->_socketType
);
2295 __CFSpinLock(&__CFActiveSocketsLock
);
2296 if (NULL
== __CFReadSockets
) __CFSocketInitializeSockets();
2297 __CFSpinUnlock(&__CFActiveSocketsLock
);
2298 __CFSpinLock(&__CFAllSocketsLock
);
2299 if (NULL
== __CFAllSockets
) {
2300 __CFAllSockets
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, &kCFTypeDictionaryValueCallBacks
);
2302 if (INVALID_SOCKET
!= sock
&& CFDictionaryGetValueIfPresent(__CFAllSockets
, (void *)(uintptr_t)sock
, (const void **)&memory
)) {
2303 if (useExistingInstance
) {
2304 __CFSpinUnlock(&__CFAllSocketsLock
);
2308 #if defined(LOG_CFSOCKET)
2309 fprintf(stdout
, "useExistingInstance is FALSE, removing existing instance %p from __CFAllSockets\n", memory
);
2311 __CFSpinUnlock(&__CFAllSocketsLock
);
2312 CFSocketInvalidate(memory
);
2313 __CFSpinLock(&__CFAllSocketsLock
);
2316 memory
= (CFSocketRef
)_CFRuntimeCreateInstance(allocator
, CFSocketGetTypeID(), sizeof(struct __CFSocket
) - sizeof(CFRuntimeBase
), NULL
);
2317 if (NULL
== memory
) {
2318 __CFSpinUnlock(&__CFAllSocketsLock
);
2321 __CFSocketSetCallBackTypes(memory
, callBackTypes
);
2322 if (INVALID_SOCKET
!= sock
) __CFSocketSetValid(memory
);
2323 __CFSocketUnsetWriteSignalled(memory
);
2324 __CFSocketUnsetReadSignalled(memory
);
2325 memory
->_f
.client
= ((callBackTypes
& (~kCFSocketConnectCallBack
)) & (~kCFSocketWriteCallBack
)) | kCFSocketCloseOnInvalidate
;
2326 memory
->_f
.disabled
= 0;
2327 memory
->_f
.connected
= FALSE
;
2328 memory
->_f
.writableHint
= FALSE
;
2329 memory
->_f
.closeSignaled
= FALSE
;
2330 memory
->_lock
= CFSpinLockInit
;
2331 memory
->_writeLock
= CFSpinLockInit
;
2332 memory
->_socket
= sock
;
2333 if (INVALID_SOCKET
== sock
|| 0 != getsockopt(sock
, SOL_SOCKET
, SO_TYPE
, (char *)&(memory
->_socketType
), (socklen_t
*)&typeSize
)) memory
->_socketType
= 0; // cast for WinSock bad API
2334 memory
->_errorCode
= 0;
2335 memory
->_address
= NULL
;
2336 memory
->_peerAddress
= NULL
;
2337 memory
->_socketSetCount
= 0;
2338 memory
->_source0
= NULL
;
2339 if (INVALID_SOCKET
!= sock
) {
2340 memory
->_runLoops
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
);
2342 memory
->_runLoops
= NULL
;
2344 memory
->_callout
= callout
;
2345 memory
->_dataQueue
= NULL
;
2346 memory
->_addressQueue
= NULL
;
2347 memory
->_context
.info
= 0;
2348 memory
->_context
.retain
= 0;
2349 memory
->_context
.release
= 0;
2350 memory
->_context
.copyDescription
= 0;
2351 timerclear(&memory
->_readBufferTimeout
);
2352 memory
->_readBuffer
= NULL
;
2353 memory
->_bytesToBuffer
= 0;
2354 memory
->_bytesToBufferPos
= 0;
2355 memory
->_bytesToBufferReadPos
= 0;
2356 memory
->_atEOF
= false;
2357 memory
->_bufferedReadError
= 0;
2358 memory
->_leftoverBytes
= NULL
;
2360 if (INVALID_SOCKET
!= sock
) CFDictionaryAddValue(__CFAllSockets
, (void *)(uintptr_t)sock
, memory
);
2361 if (NULL
== __CFSocketManagerThread
) __CFSocketManagerThread
= __CFStartSimpleThread(__CFSocketManager
, 0);
2362 __CFSpinUnlock(&__CFAllSocketsLock
);
2363 if (NULL
!= context
) {
2364 void *contextInfo
= context
->retain
? (void *)context
->retain(context
->info
) : context
->info
;
2365 __CFSocketLock(memory
);
2366 memory
->_context
.retain
= context
->retain
;
2367 memory
->_context
.release
= context
->release
;
2368 memory
->_context
.copyDescription
= context
->copyDescription
;
2369 memory
->_context
.info
= contextInfo
;
2370 __CFSocketUnlock(memory
);
2372 #if defined(LOG_CFSOCKET)
2373 CFLog(5, CFSTR("CFSocketCreateWithNative(): created socket %p (%d) with callbacks 0x%x"), memory
, memory
->_socket
, callBackTypes
);
2378 CFSocketRef
CFSocketCreateWithNative(CFAllocatorRef allocator
, CFSocketNativeHandle sock
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
) {
2379 return _CFSocketCreateWithNative(allocator
, sock
, callBackTypes
, callout
, context
, TRUE
);
2382 void CFSocketInvalidate(CFSocketRef s
) {
2383 // CFLog(5, CFSTR("CFSocketInvalidate(%p) starting"), s);
2385 UInt32 previousSocketManagerIteration
;
2386 __CFGenericValidateType(s
, CFSocketGetTypeID());
2387 #if defined(LOG_CFSOCKET)
2388 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
);
2391 __CFSpinLock(&__CFAllSocketsLock
);
2393 if (__CFSocketIsValid(s
)) {
2395 CFRunLoopSourceRef source0
;
2396 void *contextInfo
= NULL
;
2397 void (*contextRelease
)(const void *info
) = NULL
;
2398 __CFSocketUnsetValid(s
);
2399 __CFSocketUnsetWriteSignalled(s
);
2400 __CFSocketUnsetReadSignalled(s
);
2401 __CFSpinLock(&__CFActiveSocketsLock
);
2402 idx
= CFArrayGetFirstIndexOfValue(__CFWriteSockets
, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets
)), s
);
2404 CFArrayRemoveValueAtIndex(__CFWriteSockets
, idx
);
2405 __CFSocketClearFDForWrite(s
);
2407 // No need to clear FD's for V1 sources, since we'll just throw the whole event away
2408 idx
= CFArrayGetFirstIndexOfValue(__CFReadSockets
, CFRangeMake(0, CFArrayGetCount(__CFReadSockets
)), s
);
2410 CFArrayRemoveValueAtIndex(__CFReadSockets
, idx
);
2411 __CFSocketClearFDForRead(s
);
2413 previousSocketManagerIteration
= __CFSocketManagerIteration
;
2414 __CFSpinUnlock(&__CFActiveSocketsLock
);
2415 CFDictionaryRemoveValue(__CFAllSockets
, (void *)(uintptr_t)(s
->_socket
));
2416 if ((s
->_f
.client
& kCFSocketCloseOnInvalidate
) != 0) closesocket(s
->_socket
);
2417 s
->_socket
= INVALID_SOCKET
;
2418 if (NULL
!= s
->_peerAddress
) {
2419 CFRelease(s
->_peerAddress
);
2420 s
->_peerAddress
= NULL
;
2422 if (NULL
!= s
->_dataQueue
) {
2423 CFRelease(s
->_dataQueue
);
2424 s
->_dataQueue
= NULL
;
2426 if (NULL
!= s
->_addressQueue
) {
2427 CFRelease(s
->_addressQueue
);
2428 s
->_addressQueue
= NULL
;
2430 s
->_socketSetCount
= 0;
2432 // we'll need this later
2433 CFArrayRef runLoops
= (CFArrayRef
)CFRetain(s
->_runLoops
);
2434 CFRelease(s
->_runLoops
);
2436 s
->_runLoops
= NULL
;
2437 source0
= s
->_source0
;
2439 contextInfo
= s
->_context
.info
;
2440 contextRelease
= s
->_context
.release
;
2441 s
->_context
.info
= 0;
2442 s
->_context
.retain
= 0;
2443 s
->_context
.release
= 0;
2444 s
->_context
.copyDescription
= 0;
2445 __CFSocketUnlock(s
);
2447 // Do this after the socket unlock to avoid deadlock (10462525)
2448 for (idx
= CFArrayGetCount(runLoops
); idx
--;) {
2449 CFRunLoopWakeUp((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoops
, idx
));
2451 CFRelease(runLoops
);
2453 if (NULL
!= contextRelease
) {
2454 contextRelease(contextInfo
);
2456 if (NULL
!= source0
) {
2457 CFRunLoopSourceInvalidate(source0
);
2461 __CFSocketUnlock(s
);
2463 __CFSpinUnlock(&__CFAllSocketsLock
);
2465 #if defined(LOG_CFSOCKET)
2466 CFLog(5, CFSTR("CFSocketInvalidate(%p) done"), s
);
2470 Boolean
CFSocketIsValid(CFSocketRef s
) {
2472 __CFGenericValidateType(s
, CFSocketGetTypeID());
2473 return __CFSocketIsValid(s
);
2476 CFSocketNativeHandle
CFSocketGetNative(CFSocketRef s
) {
2478 __CFGenericValidateType(s
, CFSocketGetTypeID());
2482 CFDataRef
CFSocketCopyAddress(CFSocketRef s
) {
2484 CFDataRef result
= NULL
;
2485 __CFGenericValidateType(s
, CFSocketGetTypeID());
2487 __CFSocketEstablishAddress(s
);
2488 if (NULL
!= s
->_address
) {
2489 result
= (CFDataRef
)CFRetain(s
->_address
);
2491 __CFSocketUnlock(s
);
2492 #if defined(LOG_CFSOCKET)
2493 CFLog(5, CFSTR("CFSocketCopyAddress(): created socket %p address %@"), s
, result
);
2498 CFDataRef
CFSocketCopyPeerAddress(CFSocketRef s
) {
2500 CFDataRef result
= NULL
;
2501 __CFGenericValidateType(s
, CFSocketGetTypeID());
2503 __CFSocketEstablishPeerAddress(s
);
2504 if (NULL
!= s
->_peerAddress
) {
2505 result
= (CFDataRef
)CFRetain(s
->_peerAddress
);
2507 __CFSocketUnlock(s
);
2508 #if defined(LOG_CFSOCKET)
2509 CFLog(5, CFSTR("CFSocketCopyAddress(): created socket %p peer address %@"), s
, result
);
2514 void CFSocketGetContext(CFSocketRef s
, CFSocketContext
*context
) {
2516 __CFGenericValidateType(s
, CFSocketGetTypeID());
2517 CFAssert1(0 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__
);
2518 *context
= s
->_context
;
2521 CFOptionFlags
CFSocketGetSocketFlags(CFSocketRef s
) {
2523 __CFGenericValidateType(s
, CFSocketGetTypeID());
2524 return s
->_f
.client
;
2527 void CFSocketSetSocketFlags(CFSocketRef s
, CFOptionFlags flags
) {
2529 __CFGenericValidateType(s
, CFSocketGetTypeID());
2531 #if defined(LOG_CFSOCKET)
2532 fprintf(stdout
, "setting flags for socket %d, from 0x%x to 0x%lx\n", s
->_socket
, s
->_f
.client
, flags
);
2534 s
->_f
.client
= flags
;
2535 __CFSocketUnlock(s
);
2536 // CFLog(5, CFSTR("CFSocketSetSocketFlags(%p, 0x%x)"), s, flags);
2539 void CFSocketDisableCallBacks(CFSocketRef s
, CFOptionFlags callBackTypes
) {
2541 Boolean wakeup
= false;
2542 uint8_t readCallBackType
;
2543 __CFGenericValidateType(s
, CFSocketGetTypeID());
2545 if (__CFSocketIsValid(s
) && __CFSocketIsScheduled(s
)) {
2546 callBackTypes
&= __CFSocketCallBackTypes(s
);
2547 readCallBackType
= __CFSocketReadCallBackType(s
);
2548 s
->_f
.disabled
|= callBackTypes
;
2549 #if defined(LOG_CFSOCKET)
2550 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
);
2552 __CFSpinLock(&__CFActiveSocketsLock
);
2553 if ((readCallBackType
== kCFSocketAcceptCallBack
) || !__CFSocketIsConnectionOriented(s
)) s
->_f
.connected
= TRUE
;
2554 if (((callBackTypes
& kCFSocketWriteCallBack
) != 0) || (((callBackTypes
& kCFSocketConnectCallBack
) != 0) && !s
->_f
.connected
)) {
2555 if (__CFSocketClearFDForWrite(s
)) {
2556 // do not wake up the socket manager thread if all relevant write callbacks are disabled
2557 CFOptionFlags writeCallBacksAvailable
= __CFSocketCallBackTypes(s
) & (kCFSocketWriteCallBack
| kCFSocketConnectCallBack
);
2558 if (s
->_f
.connected
) writeCallBacksAvailable
&= ~kCFSocketConnectCallBack
;
2559 if ((s
->_f
.disabled
& writeCallBacksAvailable
) != writeCallBacksAvailable
) wakeup
= true;
2562 if (readCallBackType
!= kCFSocketNoCallBack
&& (callBackTypes
& readCallBackType
) != 0) {
2563 if (__CFSocketClearFDForRead(s
)) {
2564 // do not wake up the socket manager thread if callback type is read
2565 if (readCallBackType
!= kCFSocketReadCallBack
) wakeup
= true;
2568 __CFSpinUnlock(&__CFActiveSocketsLock
);
2570 __CFSocketUnlock(s
);
2573 // "force" means to clear the disabled bits set by DisableCallBacks and always reenable.
2574 // if (!force) we respect those bits, meaning they may stop us from enabling.
2575 // In addition, if !force we assume that the sockets have already been added to the
2576 // __CFReadSockets and __CFWriteSockets arrays. This is true because the callbacks start
2577 // enabled when the CFSocket is created (at which time we enable with force).
2578 // Called with SocketLock held, returns with it released!
2579 void __CFSocketEnableCallBacks(CFSocketRef s
, CFOptionFlags callBackTypes
, Boolean force
, uint8_t wakeupChar
) {
2581 Boolean wakeup
= FALSE
;
2582 if (!callBackTypes
) {
2583 __CFSocketUnlock(s
);
2586 if (__CFSocketIsValid(s
) && __CFSocketIsScheduled(s
)) {
2587 Boolean turnOnWrite
= FALSE
, turnOnConnect
= FALSE
, turnOnRead
= FALSE
;
2588 uint8_t readCallBackType
= __CFSocketReadCallBackType(s
);
2589 callBackTypes
&= __CFSocketCallBackTypes(s
);
2590 if (force
) s
->_f
.disabled
&= ~callBackTypes
;
2591 #if defined(LOG_CFSOCKET)
2592 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
);
2594 /* We will wait for connection only for connection-oriented, non-rendezvous sockets that are not already connected. Mark others as already connected. */
2595 if ((readCallBackType
== kCFSocketAcceptCallBack
) || !__CFSocketIsConnectionOriented(s
)) s
->_f
.connected
= TRUE
;
2597 // First figure out what to turn on
2598 if (s
->_f
.connected
|| (callBackTypes
& kCFSocketConnectCallBack
) == 0) {
2599 // if we want write callbacks and they're not disabled...
2600 if ((callBackTypes
& kCFSocketWriteCallBack
) != 0 && (s
->_f
.disabled
& kCFSocketWriteCallBack
) == 0) turnOnWrite
= TRUE
;
2602 // if we want connect callbacks and they're not disabled...
2603 if ((callBackTypes
& kCFSocketConnectCallBack
) != 0 && (s
->_f
.disabled
& kCFSocketConnectCallBack
) == 0) turnOnConnect
= TRUE
;
2605 // if we want read callbacks and they're not disabled...
2606 if (readCallBackType
!= kCFSocketNoCallBack
&& (callBackTypes
& readCallBackType
) != 0 && (s
->_f
.disabled
& kCFSocketReadCallBack
) == 0) turnOnRead
= TRUE
;
2608 // Now turn on the callbacks we've determined that we want on
2609 if (turnOnRead
|| turnOnWrite
|| turnOnConnect
) {
2610 __CFSpinLock(&__CFActiveSocketsLock
);
2611 if (turnOnWrite
|| turnOnConnect
) {
2613 SInt32 idx
= CFArrayGetFirstIndexOfValue(__CFWriteSockets
, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets
)), s
);
2614 if (kCFNotFound
== idx
) CFArrayAppendValue(__CFWriteSockets
, s
);
2615 // if (kCFNotFound == idx) CFLog(5, CFSTR("__CFSocketEnableCallBacks: put %p in __CFWriteSockets list due to force and non-presence"), s);
2617 if (__CFSocketSetFDForWrite(s
)) wakeup
= true;
2621 SInt32 idx
= CFArrayGetFirstIndexOfValue(__CFReadSockets
, CFRangeMake(0, CFArrayGetCount(__CFReadSockets
)), s
);
2622 if (kCFNotFound
== idx
) CFArrayAppendValue(__CFReadSockets
, s
);
2624 if (__CFSocketSetFDForRead(s
)) wakeup
= true;
2626 __CFSpinUnlock(&__CFActiveSocketsLock
);
2629 __CFSocketUnlock(s
);
2632 void CFSocketEnableCallBacks(CFSocketRef s
, CFOptionFlags callBackTypes
) {
2634 __CFGenericValidateType(s
, CFSocketGetTypeID());
2636 __CFSocketEnableCallBacks(s
, callBackTypes
, TRUE
, 'r');
2637 // CFLog(5, CFSTR("CFSocketEnableCallBacks(%p, 0x%x) done"), s, callBackTypes);
2640 static void __CFSocketSchedule(void *info
, CFRunLoopRef rl
, CFStringRef mode
) {
2641 CFSocketRef s
= (CFSocketRef
)info
;
2643 //??? also need to arrange delivery of all pending data
2644 if (__CFSocketIsValid(s
)) {
2645 CFMutableArrayRef runLoopsOrig
= s
->_runLoops
;
2646 CFMutableArrayRef runLoopsCopy
= CFArrayCreateMutableCopy(kCFAllocatorSystemDefault
, 0, s
->_runLoops
);
2647 CFArrayAppendValue(runLoopsCopy
, rl
);
2648 s
->_runLoops
= runLoopsCopy
;
2649 CFRelease(runLoopsOrig
);
2650 s
->_socketSetCount
++;
2651 // Since the v0 source is listened to on the SocketMgr thread, no matter how many modes it
2652 // is added to we just need to enable it there once (and _socketSetCount gives us a refCount
2653 // to know when we can finally disable it).
2654 if (1 == s
->_socketSetCount
) {
2655 #if defined(LOG_CFSOCKET)
2656 fprintf(stdout
, "scheduling socket %d\n", s
->_socket
);
2658 // CFLog(5, CFSTR("__CFSocketSchedule(%p, %p, %p)"), s, rl, mode);
2659 __CFSocketEnableCallBacks(s
, __CFSocketCallBackTypes(s
), TRUE
, 's'); // unlocks s
2661 __CFSocketUnlock(s
);
2663 __CFSocketUnlock(s
);
2666 static void __CFSocketCancel(void *info
, CFRunLoopRef rl
, CFStringRef mode
) {
2667 CFSocketRef s
= (CFSocketRef
)info
;
2670 s
->_socketSetCount
--;
2671 if (0 == s
->_socketSetCount
) {
2672 __CFSpinLock(&__CFActiveSocketsLock
);
2673 idx
= CFArrayGetFirstIndexOfValue(__CFWriteSockets
, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets
)), s
);
2675 // CFLog(5, CFSTR("__CFSocketCancel: removing %p from __CFWriteSockets list"), s);
2676 CFArrayRemoveValueAtIndex(__CFWriteSockets
, idx
);
2677 __CFSocketClearFDForWrite(s
);
2679 idx
= CFArrayGetFirstIndexOfValue(__CFReadSockets
, CFRangeMake(0, CFArrayGetCount(__CFReadSockets
)), s
);
2681 CFArrayRemoveValueAtIndex(__CFReadSockets
, idx
);
2682 __CFSocketClearFDForRead(s
);
2684 __CFSpinUnlock(&__CFActiveSocketsLock
);
2686 if (NULL
!= s
->_runLoops
) {
2687 CFMutableArrayRef runLoopsOrig
= s
->_runLoops
;
2688 CFMutableArrayRef runLoopsCopy
= CFArrayCreateMutableCopy(kCFAllocatorSystemDefault
, 0, s
->_runLoops
);
2689 idx
= CFArrayGetFirstIndexOfValue(runLoopsCopy
, CFRangeMake(0, CFArrayGetCount(runLoopsCopy
)), rl
);
2690 if (0 <= idx
) CFArrayRemoveValueAtIndex(runLoopsCopy
, idx
);
2691 s
->_runLoops
= runLoopsCopy
;
2692 CFRelease(runLoopsOrig
);
2694 __CFSocketUnlock(s
);
2697 // Note: must be called with socket lock held, then returns with it released
2698 // Used by both the v0 and v1 RunLoopSource perform routines
2699 static void __CFSocketDoCallback(CFSocketRef s
, CFDataRef data
, CFDataRef address
, CFSocketNativeHandle sock
) {
2700 CFSocketCallBack callout
= NULL
;
2701 void *contextInfo
= NULL
;
2702 SInt32 errorCode
= 0;
2703 Boolean readSignalled
= false, writeSignalled
= false, connectSignalled
= false, calledOut
= false;
2704 uint8_t readCallBackType
, callBackTypes
;
2706 callBackTypes
= __CFSocketCallBackTypes(s
);
2707 readCallBackType
= __CFSocketReadCallBackType(s
);
2708 readSignalled
= __CFSocketIsReadSignalled(s
);
2709 writeSignalled
= __CFSocketIsWriteSignalled(s
);
2710 connectSignalled
= writeSignalled
&& !s
->_f
.connected
;
2711 __CFSocketUnsetReadSignalled(s
);
2712 __CFSocketUnsetWriteSignalled(s
);
2713 callout
= s
->_callout
;
2714 contextInfo
= s
->_context
.info
;
2715 #if defined(LOG_CFSOCKET)
2716 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
);
2718 if (writeSignalled
) {
2719 errorCode
= s
->_errorCode
;
2720 s
->_f
.connected
= TRUE
;
2722 __CFSocketUnlock(s
);
2723 if ((callBackTypes
& kCFSocketConnectCallBack
) != 0) {
2724 if (connectSignalled
&& (!calledOut
|| CFSocketIsValid(s
))) {
2725 // CFLog(5, CFSTR("__CFSocketPerformV0(%p) doing connect callback, error: %d"), s, errorCode);
2727 #if defined(LOG_CFSOCKET)
2728 fprintf(stdout
, "perform calling out error %ld to socket %d\n", (long)errorCode
, s
->_socket
);
2730 if (callout
) callout(s
, kCFSocketConnectCallBack
, NULL
, &errorCode
, contextInfo
);
2733 #if defined(LOG_CFSOCKET)
2734 fprintf(stdout
, "perform calling out connect to socket %d\n", s
->_socket
);
2736 if (callout
) callout(s
, kCFSocketConnectCallBack
, NULL
, NULL
, contextInfo
);
2741 if (kCFSocketDataCallBack
== readCallBackType
) {
2742 if (NULL
!= data
&& (!calledOut
|| CFSocketIsValid(s
))) {
2743 SInt32 datalen
= CFDataGetLength(data
);
2744 #if defined(LOG_CFSOCKET)
2745 fprintf(stdout
, "perform calling out data of length %ld to socket %d\n", (long)datalen
, s
->_socket
);
2747 if (callout
) callout(s
, kCFSocketDataCallBack
, address
, data
, contextInfo
);
2749 if (0 == datalen
) CFSocketInvalidate(s
);
2751 } else if (kCFSocketAcceptCallBack
== readCallBackType
) {
2752 if (INVALID_SOCKET
!= sock
&& (!calledOut
|| CFSocketIsValid(s
))) {
2753 #if defined(LOG_CFSOCKET)
2754 fprintf(stdout
, "perform calling out accept of socket %d to socket %d\n", sock
, s
->_socket
);
2756 if (callout
) callout(s
, kCFSocketAcceptCallBack
, address
, &sock
, contextInfo
);
2759 } else if (kCFSocketReadCallBack
== readCallBackType
) {
2760 if (readSignalled
&& (!calledOut
|| CFSocketIsValid(s
))) {
2761 #if defined(LOG_CFSOCKET)
2762 fprintf(stdout
, "perform calling out read to socket %d\n", s
->_socket
);
2764 // CFLog(5, CFSTR("__CFSocketPerformV0(%p) doing read callback"), s);
2765 if (callout
) callout(s
, kCFSocketReadCallBack
, NULL
, NULL
, contextInfo
);
2769 if ((callBackTypes
& kCFSocketWriteCallBack
) != 0) {
2770 if (writeSignalled
&& !errorCode
&& (!calledOut
|| CFSocketIsValid(s
))) {
2771 #if defined(LOG_CFSOCKET)
2772 fprintf(stdout
, "perform calling out write to socket %d\n", s
->_socket
);
2774 // CFLog(5, CFSTR("__CFSocketPerformV0(%p) doing write callback"), s);
2775 if (callout
) callout(s
, kCFSocketWriteCallBack
, NULL
, NULL
, contextInfo
);
2781 static void __CFSocketPerformV0(void *info
) {
2782 CFSocketRef s
= (CFSocketRef
)info
;
2783 CFDataRef data
= NULL
;
2784 CFDataRef address
= NULL
;
2785 CFSocketNativeHandle sock
= INVALID_SOCKET
;
2786 uint8_t readCallBackType
, callBackTypes
;
2787 CFRunLoopRef rl
= NULL
;
2788 // CFLog(5, CFSTR("__CFSocketPerformV0(%p) starting"), s);
2791 if (!__CFSocketIsValid(s
)) {
2792 __CFSocketUnlock(s
);
2795 callBackTypes
= __CFSocketCallBackTypes(s
);
2796 readCallBackType
= __CFSocketReadCallBackType(s
);
2797 CFOptionFlags callBacksSignalled
= 0;
2798 if (__CFSocketIsReadSignalled(s
)) callBacksSignalled
|= readCallBackType
;
2799 if (__CFSocketIsWriteSignalled(s
)) callBacksSignalled
|= kCFSocketWriteCallBack
;
2801 if (kCFSocketDataCallBack
== readCallBackType
) {
2802 if (NULL
!= s
->_dataQueue
&& 0 < CFArrayGetCount(s
->_dataQueue
)) {
2803 data
= (CFDataRef
)CFArrayGetValueAtIndex(s
->_dataQueue
, 0);
2805 CFArrayRemoveValueAtIndex(s
->_dataQueue
, 0);
2806 address
= (CFDataRef
)CFArrayGetValueAtIndex(s
->_addressQueue
, 0);
2808 CFArrayRemoveValueAtIndex(s
->_addressQueue
, 0);
2810 } else if (kCFSocketAcceptCallBack
== readCallBackType
) {
2811 if (NULL
!= s
->_dataQueue
&& 0 < CFArrayGetCount(s
->_dataQueue
)) {
2812 sock
= (CFSocketNativeHandle
)(uintptr_t)CFArrayGetValueAtIndex(s
->_dataQueue
, 0);
2813 CFArrayRemoveValueAtIndex(s
->_dataQueue
, 0);
2814 address
= (CFDataRef
)CFArrayGetValueAtIndex(s
->_addressQueue
, 0);
2816 CFArrayRemoveValueAtIndex(s
->_addressQueue
, 0);
2820 __CFSocketDoCallback(s
, data
, address
, sock
); // does __CFSocketUnlock(s)
2821 if (NULL
!= data
) CFRelease(data
);
2822 if (NULL
!= address
) CFRelease(address
);
2825 if (__CFSocketIsValid(s
) && kCFSocketNoCallBack
!= readCallBackType
) {
2826 // if there's still more data, we want to wake back up right away
2827 if ((kCFSocketDataCallBack
== readCallBackType
|| kCFSocketAcceptCallBack
== readCallBackType
) && NULL
!= s
->_dataQueue
&& 0 < CFArrayGetCount(s
->_dataQueue
)) {
2828 #if defined(LOG_CFSOCKET)
2829 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
);
2831 CFRunLoopSourceSignal(s
->_source0
);
2832 CFMutableArrayRef runLoopsOrig
= (CFMutableArrayRef
)CFRetain(s
->_runLoops
);
2833 CFMutableArrayRef runLoopsCopy
= CFArrayCreateMutableCopy(kCFAllocatorSystemDefault
, 0, s
->_runLoops
);
2834 CFRunLoopSourceRef source0
= s
->_source0
;
2835 if (NULL
!= source0
&& !CFRunLoopSourceIsValid(source0
)) {
2838 if (source0
) CFRetain(source0
);
2839 __CFSocketUnlock(s
);
2840 rl
= __CFSocketCopyRunLoopToWakeUp(source0
, runLoopsCopy
);
2841 if (source0
) CFRelease(source0
);
2843 if (runLoopsOrig
== s
->_runLoops
) {
2844 s
->_runLoops
= runLoopsCopy
;
2845 runLoopsCopy
= NULL
;
2846 CFRelease(runLoopsOrig
);
2848 CFRelease(runLoopsOrig
);
2849 if (runLoopsCopy
) CFRelease(runLoopsCopy
);
2852 // Only reenable callbacks that are auto-reenabled
2853 __CFSocketEnableCallBacks(s
, callBacksSignalled
& s
->_f
.client
, FALSE
, 'p'); // unlocks s
2856 CFRunLoopWakeUp(rl
);
2859 // CFLog(5, CFSTR("__CFSocketPerformV0(%p) done"), s);
2862 CFRunLoopSourceRef
CFSocketCreateRunLoopSource(CFAllocatorRef allocator
, CFSocketRef s
, CFIndex order
) {
2864 CFRunLoopSourceRef result
= NULL
;
2865 __CFGenericValidateType(s
, CFSocketGetTypeID());
2867 if (__CFSocketIsValid(s
)) {
2868 if (NULL
!= s
->_source0
&& !CFRunLoopSourceIsValid(s
->_source0
)) {
2869 CFRelease(s
->_source0
);
2872 if (NULL
== s
->_source0
) {
2873 CFRunLoopSourceContext context
;
2874 context
.version
= 0;
2876 context
.retain
= CFRetain
;
2877 context
.release
= CFRelease
;
2878 context
.copyDescription
= CFCopyDescription
;
2879 context
.equal
= CFEqual
;
2880 context
.hash
= CFHash
;
2881 context
.schedule
= __CFSocketSchedule
;
2882 context
.cancel
= __CFSocketCancel
;
2883 context
.perform
= __CFSocketPerformV0
;
2884 s
->_source0
= CFRunLoopSourceCreate(allocator
, order
, &context
);
2886 CFRetain(s
->_source0
); /* This retain is for the receiver */
2887 result
= s
->_source0
;
2889 __CFSocketUnlock(s
);
2893 #endif /* NEW_SOCKET */
2897 static uint16_t __CFSocketDefaultNameRegistryPortNumber
= 2454;
2899 CONST_STRING_DECL(kCFSocketCommandKey
, "Command")
2900 CONST_STRING_DECL(kCFSocketNameKey
, "Name")
2901 CONST_STRING_DECL(kCFSocketValueKey
, "Value")
2902 CONST_STRING_DECL(kCFSocketResultKey
, "Result")
2903 CONST_STRING_DECL(kCFSocketErrorKey
, "Error")
2904 CONST_STRING_DECL(kCFSocketRegisterCommand
, "Register")
2905 CONST_STRING_DECL(kCFSocketRetrieveCommand
, "Retrieve")
2906 CONST_STRING_DECL(__kCFSocketRegistryRequestRunLoopMode
, "CFSocketRegistryRequest")
2908 static CFSpinLock_t __CFSocketWriteLock_
= CFSpinLockInit
;
2909 //#warning can only send on one socket at a time now
2911 CF_INLINE
void __CFSocketWriteLock(CFSocketRef s
) {
2912 __CFSpinLock(& __CFSocketWriteLock_
);
2915 CF_INLINE
void __CFSocketWriteUnlock(CFSocketRef s
) {
2916 __CFSpinUnlock(& __CFSocketWriteLock_
);
2921 CF_INLINE CFIndex
__CFSocketFdGetSize(CFDataRef fdSet
) {
2922 return NBBY
* CFDataGetLength(fdSet
);
2925 CF_INLINE Boolean
__CFSocketFdSet(CFSocketNativeHandle sock
, CFMutableDataRef fdSet
) {
2926 /* returns true if a change occurred, false otherwise */
2927 Boolean retval
= false;
2928 if (INVALID_SOCKET
!= sock
&& 0 <= sock
) {
2929 CFIndex numFds
= NBBY
* CFDataGetLength(fdSet
);
2931 if (sock
>= numFds
) {
2932 CFIndex oldSize
= numFds
/ NFDBITS
, newSize
= (sock
+ NFDBITS
) / NFDBITS
, changeInBytes
= (newSize
- oldSize
) * sizeof(fd_mask
);
2933 CFDataIncreaseLength(fdSet
, changeInBytes
);
2934 fds_bits
= (fd_mask
*)CFDataGetMutableBytePtr(fdSet
);
2935 memset(fds_bits
+ oldSize
, 0, changeInBytes
);
2937 fds_bits
= (fd_mask
*)CFDataGetMutableBytePtr(fdSet
);
2939 if (!FD_ISSET(sock
, (fd_set
*)fds_bits
)) {
2941 FD_SET(sock
, (fd_set
*)fds_bits
);
2949 //??? need timeout, error handling, retries
2950 CFSocketError
CFSocketSendData(CFSocketRef s
, CFDataRef address
, CFDataRef data
, CFTimeInterval timeout
) {
2952 const uint8_t *dataptr
, *addrptr
= NULL
;
2953 SInt32 datalen
, addrlen
= 0, size
= 0;
2954 CFSocketNativeHandle sock
= INVALID_SOCKET
;
2956 __CFGenericValidateType(s
, CFSocketGetTypeID());
2958 addrptr
= CFDataGetBytePtr(address
);
2959 addrlen
= CFDataGetLength(address
);
2961 dataptr
= CFDataGetBytePtr(data
);
2962 datalen
= CFDataGetLength(data
);
2963 if (CFSocketIsValid(s
)) sock
= CFSocketGetNative(s
);
2964 if (INVALID_SOCKET
!= sock
) {
2966 __CFSocketWriteLock(s
);
2967 tv
.tv_sec
= (timeout
<= 0.0 || (CFTimeInterval
)INT_MAX
<= timeout
) ? INT_MAX
: (int)floor(timeout
);
2968 tv
.tv_usec
= (int)floor(1.0e+6 * (timeout
- floor(timeout
)));
2969 setsockopt(sock
, SOL_SOCKET
, SO_SNDTIMEO
, (char *)&tv
, sizeof(tv
)); // cast for WinSock bad API
2970 if (NULL
!= addrptr
&& 0 < addrlen
) {
2971 size
= sendto(sock
, (char *)dataptr
, datalen
, 0, (struct sockaddr
*)addrptr
, addrlen
);
2973 size
= send(sock
, (char *)dataptr
, datalen
, 0);
2975 #if defined(LOG_CFSOCKET)
2976 fprintf(stdout
, "wrote %ld bytes to socket %d\n", (long)size
, sock
);
2978 __CFSocketWriteUnlock(s
);
2981 return (size
> 0) ? kCFSocketSuccess
: kCFSocketError
;
2984 CFSocketError
CFSocketSetAddress(CFSocketRef s
, CFDataRef address
) {
2986 struct sockaddr
*name
;
2988 __CFGenericValidateType(s
, CFSocketGetTypeID());
2989 if (NULL
== address
) return kCFSocketError
;
2990 if (!CFSocketIsValid(s
)) return kCFSocketError
;
2992 name
= (struct sockaddr
*)CFDataGetBytePtr(address
);
2993 namelen
= (socklen_t
)CFDataGetLength(address
);
2994 if (!name
|| namelen
<= 0) return kCFSocketError
;
2996 CFSocketNativeHandle sock
= CFSocketGetNative(s
);
2997 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2998 // Verify that the namelen is correct. If not, we have to fix it up. Developers will often incorrectly use 0 or strlen(path). See 9217961 and the second half of 9098274.
2999 // Max size is a size byte, plus family byte, plus path of 255, plus a null byte.
3001 if (namelen
> 2 && name
->sa_family
== AF_UNIX
) {
3002 // Don't use the SUN_LEN macro, because strnlen is safer and we know the max length of the string (from CFData, minus 2 bytes for len and addr)
3003 socklen_t realLength
= (sizeof(*((struct sockaddr_un
*)name
)) - sizeof(((struct sockaddr_un
*)name
)->sun_path
) + strnlen(((struct sockaddr_un
*)name
)->sun_path
, namelen
- 2));
3004 if (realLength
> 255) return kCFSocketError
;
3006 // For a UNIX domain socket, we must pass the value of name.sun_len to bind in order for getsockname() to return a result that makes sense.
3007 namelen
= (socklen_t
)(((struct sockaddr_un
*)name
)->sun_len
);
3009 if (realLength
!= namelen
) {
3010 // We got a different answer for length than was supplied by the caller. Fix it up so we don't end up truncating the path.
3011 CFLog(kCFLogLevelWarning
, CFSTR("WARNING: The sun_len field of a sockaddr_un structure passed to CFSocketSetAddress was not set correctly using the SUN_LEN macro."));
3012 memcpy(newName
, name
, realLength
);
3013 namelen
= realLength
;
3014 ((struct sockaddr_un
*)newName
)->sun_len
= realLength
;
3015 name
= (struct sockaddr
*)newName
;
3019 int result
= bind(sock
, name
, namelen
);
3023 //??? should return errno
3024 return (CFIndex
)result
;
3027 CFSocketError
CFSocketConnectToAddress(CFSocketRef s
, CFDataRef address
, CFTimeInterval timeout
) {
3029 //??? need error handling, retries
3030 const uint8_t *name
;
3031 SInt32 namelen
, result
= -1, connect_err
= 0, select_err
= 0;
3032 UInt32 yes
= 1, no
= 0;
3033 Boolean wasBlocking
= true;
3035 __CFGenericValidateType(s
, CFSocketGetTypeID());
3036 if (!CFSocketIsValid(s
)) return kCFSocketError
;
3037 name
= CFDataGetBytePtr(address
);
3038 namelen
= CFDataGetLength(address
);
3039 if (!name
|| namelen
<= 0) return kCFSocketError
;
3040 CFSocketNativeHandle sock
= CFSocketGetNative(s
);
3042 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
3043 SInt32 flags
= fcntl(sock
, F_GETFL
, 0);
3044 if (flags
>= 0) wasBlocking
= ((flags
& O_NONBLOCK
) == 0);
3045 if (wasBlocking
&& (timeout
> 0.0 || timeout
< 0.0)) ioctlsocket(sock
, FIONBIO
, (u_long
*)&yes
);
3047 // You can set but not get this flag in WIN32, so assume it was in non-blocking mode.
3048 // The downside is that when we leave this routine we'll leave it non-blocking,
3049 // whether it started that way or not.
3051 if (timeout
> 0.0 || timeout
< 0.0) ioctlsocket(sock
, FIONBIO
, (u_long
*)&yes
);
3052 wasBlocking
= false;
3054 result
= connect(sock
, (struct sockaddr
*)name
, namelen
);
3056 connect_err
= __CFSocketLastError();
3057 #if DEPLOYMENT_TARGET_WINDOWS
3058 if (connect_err
== WSAEWOULDBLOCK
) connect_err
= EINPROGRESS
;
3061 #if defined(LOG_CFSOCKET)
3062 fprintf(stdout
, "connection attempt returns %d error %d on socket %d (flags 0x%x blocking %d)\n", (int) result
, (int) connect_err
, sock
, (int) flags
, wasBlocking
);
3064 if (EINPROGRESS
== connect_err
&& timeout
>= 0.0) {
3065 /* select on socket */
3067 int error_size
= sizeof(select_err
);
3069 CFMutableDataRef fds
= CFDataCreateMutable(kCFAllocatorSystemDefault
, 0);
3070 __CFSocketFdSet(sock
, fds
);
3071 tv
.tv_sec
= (timeout
<= 0.0 || (CFTimeInterval
)INT_MAX
<= timeout
) ? INT_MAX
: (int)floor(timeout
);
3072 tv
.tv_usec
= (int)floor(1.0e+6 * (timeout
- floor(timeout
)));
3073 nrfds
= select(__CFSocketFdGetSize(fds
), NULL
, (fd_set
*)CFDataGetMutableBytePtr(fds
), NULL
, &tv
);
3075 select_err
= __CFSocketLastError();
3077 } else if (nrfds
== 0) {
3080 if (0 != getsockopt(sock
, SOL_SOCKET
, SO_ERROR
, (char *)&select_err
, (socklen_t
*)&error_size
)) select_err
= 0;
3081 result
= (select_err
== 0) ? 0 : -1;
3084 #if defined(LOG_CFSOCKET)
3085 fprintf(stdout
, "timed connection attempt %s on socket %d, result %d, select returns %d error %d\n", (result
== 0) ? "succeeds" : "fails", sock
, (int) result
, (int) nrfds
, (int) select_err
);
3088 if (wasBlocking
&& (timeout
> 0.0 || timeout
< 0.0)) ioctlsocket(sock
, FIONBIO
, (u_long
*)&no
);
3089 if (EINPROGRESS
== connect_err
&& timeout
< 0.0) {
3091 #if defined(LOG_CFSOCKET)
3092 fprintf(stdout
, "connection attempt continues in background on socket %d\n", sock
);
3096 //??? should return errno
3100 CFSocketRef
CFSocketCreate(CFAllocatorRef allocator
, SInt32 protocolFamily
, SInt32 socketType
, SInt32 protocol
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
) {
3102 CFSocketNativeHandle sock
= INVALID_SOCKET
;
3103 CFSocketRef s
= NULL
;
3104 if (0 >= protocolFamily
) protocolFamily
= PF_INET
;
3105 if (PF_INET
== protocolFamily
) {
3106 if (0 >= socketType
) socketType
= SOCK_STREAM
;
3107 if (0 >= protocol
&& SOCK_STREAM
== socketType
) protocol
= IPPROTO_TCP
;
3108 if (0 >= protocol
&& SOCK_DGRAM
== socketType
) protocol
= IPPROTO_UDP
;
3110 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
3111 if (PF_LOCAL
== protocolFamily
&& 0 >= socketType
) socketType
= SOCK_STREAM
;
3113 #if DEPLOYMENT_TARGET_WINDOWS
3114 // make sure we've called proper Win32 startup facilities before socket()
3115 __CFSocketInitializeWinSock();
3117 sock
= socket(protocolFamily
, socketType
, protocol
);
3118 if (INVALID_SOCKET
!= sock
) {
3119 s
= CFSocketCreateWithNative(allocator
, sock
, callBackTypes
, callout
, context
);
3124 CFSocketRef
CFSocketCreateWithSocketSignature(CFAllocatorRef allocator
, const CFSocketSignature
*signature
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
) {
3126 CFSocketRef s
= CFSocketCreate(allocator
, signature
->protocolFamily
, signature
->socketType
, signature
->protocol
, callBackTypes
, callout
, context
);
3127 if (NULL
!= s
&& (!CFSocketIsValid(s
) || kCFSocketSuccess
!= CFSocketSetAddress(s
, signature
->address
))) {
3128 CFSocketInvalidate(s
);
3135 CFSocketRef
CFSocketCreateConnectedToSocketSignature(CFAllocatorRef allocator
, const CFSocketSignature
*signature
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
, CFTimeInterval timeout
) {
3137 CFSocketRef s
= CFSocketCreate(allocator
, signature
->protocolFamily
, signature
->socketType
, signature
->protocol
, callBackTypes
, callout
, context
);
3138 if (NULL
!= s
&& (!CFSocketIsValid(s
) || kCFSocketSuccess
!= CFSocketConnectToAddress(s
, signature
->address
, timeout
))) {
3139 CFSocketInvalidate(s
);
3147 CFSocketError
*error
;
3148 CFPropertyListRef
*value
;
3150 } __CFSocketNameRegistryResponse
;
3152 static void __CFSocketHandleNameRegistryReply(CFSocketRef s
, CFSocketCallBackType type
, CFDataRef address
, const void *data
, void *info
) {
3153 CFDataRef replyData
= (CFDataRef
)data
;
3154 __CFSocketNameRegistryResponse
*response
= (__CFSocketNameRegistryResponse
*)info
;
3155 CFDictionaryRef replyDictionary
= NULL
;
3156 CFPropertyListRef value
;
3157 replyDictionary
= (CFDictionaryRef
)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault
, replyData
, kCFPropertyListImmutable
, NULL
);
3158 if (NULL
!= response
->error
) *(response
->error
) = kCFSocketError
;
3159 if (NULL
!= replyDictionary
) {
3160 if (CFGetTypeID((CFTypeRef
)replyDictionary
) == CFDictionaryGetTypeID() && NULL
!= (value
= CFDictionaryGetValue(replyDictionary
, kCFSocketResultKey
))) {
3161 if (NULL
!= response
->error
) *(response
->error
) = kCFSocketSuccess
;
3162 if (NULL
!= response
->value
) *(response
->value
) = CFRetain(value
);
3163 if (NULL
!= response
->address
) *(response
->address
) = address
? CFDataCreateCopy(kCFAllocatorSystemDefault
, address
) : NULL
;
3165 CFRelease(replyDictionary
);
3167 CFSocketInvalidate(s
);
3170 static void __CFSocketSendNameRegistryRequest(CFSocketSignature
*signature
, CFDictionaryRef requestDictionary
, __CFSocketNameRegistryResponse
*response
, CFTimeInterval timeout
) {
3171 CFDataRef requestData
= NULL
;
3172 CFSocketContext context
= {0, response
, NULL
, NULL
, NULL
};
3173 CFSocketRef s
= NULL
;
3174 CFRunLoopSourceRef source
= NULL
;
3175 if (NULL
!= response
->error
) *(response
->error
) = kCFSocketError
;
3176 requestData
= CFPropertyListCreateXMLData(kCFAllocatorSystemDefault
, requestDictionary
);
3177 if (NULL
!= requestData
) {
3178 if (NULL
!= response
->error
) *(response
->error
) = kCFSocketTimeout
;
3179 s
= CFSocketCreateConnectedToSocketSignature(kCFAllocatorSystemDefault
, signature
, kCFSocketDataCallBack
, __CFSocketHandleNameRegistryReply
, &context
, timeout
);
3181 if (kCFSocketSuccess
== CFSocketSendData(s
, NULL
, requestData
, timeout
)) {
3182 source
= CFSocketCreateRunLoopSource(kCFAllocatorSystemDefault
, s
, 0);
3183 CFRunLoopAddSource(CFRunLoopGetCurrent(), source
, __kCFSocketRegistryRequestRunLoopMode
);
3184 CFRunLoopRunInMode(__kCFSocketRegistryRequestRunLoopMode
, timeout
, false);
3187 CFSocketInvalidate(s
);
3190 CFRelease(requestData
);
3194 static void __CFSocketValidateSignature(const CFSocketSignature
*providedSignature
, CFSocketSignature
*signature
, uint16_t defaultPortNumber
) {
3195 struct sockaddr_in sain
, *sainp
;
3196 memset(&sain
, 0, sizeof(sain
));
3197 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
3198 sain
.sin_len
= sizeof(sain
);
3200 sain
.sin_family
= AF_INET
;
3201 sain
.sin_port
= htons(__CFSocketDefaultNameRegistryPortNumber
);
3202 sain
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
3203 if (NULL
== providedSignature
) {
3204 signature
->protocolFamily
= PF_INET
;
3205 signature
->socketType
= SOCK_STREAM
;
3206 signature
->protocol
= IPPROTO_TCP
;
3207 signature
->address
= CFDataCreate(kCFAllocatorSystemDefault
, (uint8_t *)&sain
, sizeof(sain
));
3209 signature
->protocolFamily
= providedSignature
->protocolFamily
;
3210 signature
->socketType
= providedSignature
->socketType
;
3211 signature
->protocol
= providedSignature
->protocol
;
3212 if (0 >= signature
->protocolFamily
) signature
->protocolFamily
= PF_INET
;
3213 if (PF_INET
== signature
->protocolFamily
) {
3214 if (0 >= signature
->socketType
) signature
->socketType
= SOCK_STREAM
;
3215 if (0 >= signature
->protocol
&& SOCK_STREAM
== signature
->socketType
) signature
->protocol
= IPPROTO_TCP
;
3216 if (0 >= signature
->protocol
&& SOCK_DGRAM
== signature
->socketType
) signature
->protocol
= IPPROTO_UDP
;
3218 if (NULL
== providedSignature
->address
) {
3219 signature
->address
= CFDataCreate(kCFAllocatorSystemDefault
, (uint8_t *)&sain
, sizeof(sain
));
3221 sainp
= (struct sockaddr_in
*)CFDataGetBytePtr(providedSignature
->address
);
3222 if ((int)sizeof(struct sockaddr_in
) <= CFDataGetLength(providedSignature
->address
) && (AF_INET
== sainp
->sin_family
|| 0 == sainp
->sin_family
)) {
3223 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
3224 sain
.sin_len
= sizeof(sain
);
3226 sain
.sin_family
= AF_INET
;
3227 sain
.sin_port
= sainp
->sin_port
;
3228 if (0 == sain
.sin_port
) sain
.sin_port
= htons(defaultPortNumber
);
3229 sain
.sin_addr
.s_addr
= sainp
->sin_addr
.s_addr
;
3230 if (htonl(INADDR_ANY
) == sain
.sin_addr
.s_addr
) sain
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
3231 signature
->address
= CFDataCreate(kCFAllocatorSystemDefault
, (uint8_t *)&sain
, sizeof(sain
));
3233 signature
->address
= (CFDataRef
)CFRetain(providedSignature
->address
);
3239 CFSocketError
CFSocketRegisterValue(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
, CFPropertyListRef value
) {
3240 CFSocketSignature signature
;
3241 CFMutableDictionaryRef dictionary
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 3, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
3242 CFSocketError retval
= kCFSocketError
;
3243 __CFSocketNameRegistryResponse response
= {&retval
, NULL
, NULL
};
3244 CFDictionaryAddValue(dictionary
, kCFSocketCommandKey
, kCFSocketRegisterCommand
);
3245 CFDictionaryAddValue(dictionary
, kCFSocketNameKey
, name
);
3246 if (NULL
!= value
) CFDictionaryAddValue(dictionary
, kCFSocketValueKey
, value
);
3247 __CFSocketValidateSignature(nameServerSignature
, &signature
, __CFSocketDefaultNameRegistryPortNumber
);
3248 __CFSocketSendNameRegistryRequest(&signature
, dictionary
, &response
, timeout
);
3249 CFRelease(dictionary
);
3250 CFRelease(signature
.address
);
3254 CFSocketError
CFSocketCopyRegisteredValue(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
, CFPropertyListRef
*value
, CFDataRef
*serverAddress
) {
3255 CFSocketSignature signature
;
3256 CFMutableDictionaryRef dictionary
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 2, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
3257 CFSocketError retval
= kCFSocketError
;
3258 __CFSocketNameRegistryResponse response
= {&retval
, value
, serverAddress
};
3259 CFDictionaryAddValue(dictionary
, kCFSocketCommandKey
, kCFSocketRetrieveCommand
);
3260 CFDictionaryAddValue(dictionary
, kCFSocketNameKey
, name
);
3261 __CFSocketValidateSignature(nameServerSignature
, &signature
, __CFSocketDefaultNameRegistryPortNumber
);
3262 __CFSocketSendNameRegistryRequest(&signature
, dictionary
, &response
, timeout
);
3263 CFRelease(dictionary
);
3264 CFRelease(signature
.address
);
3268 CFSocketError
CFSocketRegisterSocketSignature(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
, const CFSocketSignature
*signature
) {
3269 CFSocketSignature validatedSignature
;
3270 CFMutableDataRef data
= NULL
;
3271 CFSocketError retval
;
3274 if (NULL
== signature
) {
3275 retval
= CFSocketUnregister(nameServerSignature
, timeout
, name
);
3277 __CFSocketValidateSignature(signature
, &validatedSignature
, 0);
3278 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
) {
3279 retval
= kCFSocketError
;
3281 data
= CFDataCreateMutable(kCFAllocatorSystemDefault
, sizeof(bytes
) + length
);
3282 bytes
[0] = validatedSignature
.protocolFamily
;
3283 bytes
[1] = validatedSignature
.socketType
;
3284 bytes
[2] = validatedSignature
.protocol
;
3286 CFDataAppendBytes(data
, bytes
, sizeof(bytes
));
3287 CFDataAppendBytes(data
, CFDataGetBytePtr(validatedSignature
.address
), length
);
3288 retval
= CFSocketRegisterValue(nameServerSignature
, timeout
, name
, data
);
3291 CFRelease(validatedSignature
.address
);
3296 CFSocketError
CFSocketCopyRegisteredSocketSignature(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
, CFSocketSignature
*signature
, CFDataRef
*nameServerAddress
) {
3297 CFDataRef data
= NULL
;
3298 CFSocketSignature returnedSignature
;
3299 const uint8_t *ptr
= NULL
, *aptr
= NULL
;
3302 CFDataRef serverAddress
= NULL
;
3303 CFSocketError retval
= CFSocketCopyRegisteredValue(nameServerSignature
, timeout
, name
, (CFPropertyListRef
*)&data
, &serverAddress
);
3304 if (NULL
== data
|| CFGetTypeID(data
) != CFDataGetTypeID() || NULL
== (ptr
= CFDataGetBytePtr(data
)) || (length
= CFDataGetLength(data
)) < 4) retval
= kCFSocketError
;
3305 if (kCFSocketSuccess
== retval
&& NULL
!= signature
) {
3306 returnedSignature
.protocolFamily
= (SInt32
)*ptr
++;
3307 returnedSignature
.socketType
= (SInt32
)*ptr
++;
3308 returnedSignature
.protocol
= (SInt32
)*ptr
++;
3310 returnedSignature
.address
= CFDataCreate(kCFAllocatorSystemDefault
, ptr
, length
- 4);
3311 __CFSocketValidateSignature(&returnedSignature
, signature
, 0);
3312 CFRelease(returnedSignature
.address
);
3313 ptr
= CFDataGetBytePtr(signature
->address
);
3314 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
) {
3315 CFMutableDataRef address
= CFDataCreateMutableCopy(kCFAllocatorSystemDefault
, CFDataGetLength(signature
->address
), signature
->address
);
3316 mptr
= CFDataGetMutableBytePtr(address
);
3317 ((struct sockaddr_in
*)mptr
)->sin_addr
= ((struct sockaddr_in
*)aptr
)->sin_addr
;
3318 CFRelease(signature
->address
);
3319 signature
->address
= address
;
3321 if (NULL
!= nameServerAddress
) *nameServerAddress
= serverAddress
? (CFDataRef
)CFRetain(serverAddress
) : NULL
;
3323 if (NULL
!= data
) CFRelease(data
);
3324 if (NULL
!= serverAddress
) CFRelease(serverAddress
);
3328 CFSocketError
CFSocketUnregister(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
) {
3329 return CFSocketRegisterValue(nameServerSignature
, timeout
, name
, NULL
);
3332 CF_EXPORT
void CFSocketSetDefaultNameRegistryPortNumber(uint16_t port
) {
3333 __CFSocketDefaultNameRegistryPortNumber
= port
;
3336 CF_EXPORT
uint16_t CFSocketGetDefaultNameRegistryPortNumber(void) {
3337 return __CFSocketDefaultNameRegistryPortNumber
;