2 * Copyright (c) 2015 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-2014, 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 static dispatch_once_t initOnce;
214 dispatch_once(&initOnce, ^{
215 __kCFSocketTypeID = _CFRuntimeRegisterClass(&__CFSocketClass); // initOnce covered
216 __CFAllSockets = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
218 int ret1 = getrlimit(RLIMIT_NOFILE, &lim1);
219 int mib[] = {CTL_KERN, KERN_MAXFILESPERPROC};
221 size_t len = sizeof(int);
222 int ret0 = sysctl(mib, 2, &maxfd, &len, NULL, 0);
223 if (0 == ret0 && 0 == ret1 && lim1.rlim_max < maxfd) maxfd = lim1.rlim_max;
224 if (0 == ret1 && lim1.rlim_cur < maxfd) {
225 struct rlimit lim2 = lim1;
226 lim2.rlim_cur += 2304;
227 if (maxfd < lim2.rlim_cur) lim2.rlim_cur = maxfd;
228 setrlimit(RLIMIT_NOFILE, &lim2);
229 // we try, but do not go to extraordinary measures
232 return __kCFSocketTypeID;
235 CFSocketRef CFSocketCreateWithNative(CFAllocatorRef allocator, CFSocketNativeHandle ufd, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context) {
236 CHECK_FOR_FORK_RET(NULL);
238 CFSocketGetTypeID(); // cause initialization if necessary
241 int ret = fstat(ufd, &statbuf);
242 if (ret < 0) ufd = INVALID_SOCKET;
244 Boolean sane = false;
245 if (INVALID_SOCKET != ufd) {
246 uint32_t type = (statbuf.st_mode & S_IFMT);
247 sane = (S_IFSOCK == type) || (S_IFIFO == type) || (S_IFCHR == type);
249 CFLog(kCFLogLevelWarning, CFSTR("*** CFSocketCreateWithNative(): creating CFSocket with silly fd type (%07o) -- may or may not work"), type);
253 if (INVALID_SOCKET != ufd) {
254 Boolean canHandle = false;
255 int tmp_kq = kqueue();
258 EV_SET(&ev[0], ufd, EVFILT_READ, EV_ADD, 0, 0, 0);
259 EV_SET(&ev[1], ufd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
260 int ret = kevent(tmp_kq, ev, 2, NULL, 0, NULL);
261 canHandle = (0 <= ret); // if kevent(ADD) succeeds, can handle
264 if (1 && !canHandle) {
265 CFLog(kCFLogLevelWarning, CFSTR("*** CFSocketCreateWithNative(): creating CFSocket with unsupported fd type -- may or may not work"));
269 if (INVALID_SOCKET == ufd) {
270 // Historically, bad ufd was allowed, but gave an uncached and already-invalid CFSocketRef
271 SInt32 size = sizeof(struct __CFSocket) - sizeof(CFRuntimeBase);
272 CFSocketRef memory = (CFSocketRef)_CFRuntimeCreateInstance(allocator, CFSocketGetTypeID(), size, NULL);
273 if (NULL == memory) {
276 memory->_callout = callout;
277 memory->_state = kCFSocketStateInvalid;
281 __block CFSocketRef sock = NULL;
282 dispatch_sync(__sockQueue(), ^{
283 for (CFIndex idx = 0, cnt = CFArrayGetCount(__CFAllSockets); idx < cnt; idx++) {
284 CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(__CFAllSockets, idx);
285 if (s->_shared->_socket == ufd) {
292 SInt32 size = sizeof(struct __CFSocket) - sizeof(CFRuntimeBase);
293 CFSocketRef memory = (CFSocketRef)_CFRuntimeCreateInstance(allocator, CFSocketGetTypeID(), size, NULL);
294 if (NULL == memory) {
299 if (INVALID_SOCKET != ufd) {
300 socklen_t typeSize = sizeof(socketType);
301 int ret = getsockopt(ufd, SOL_SOCKET, SO_TYPE, (void *)&socketType, (socklen_t *)&typeSize);
302 if (ret < 0) socketType = 0;
305 memory->_rsuspended = true;
306 memory->_wsuspended = true;
307 memory->_readable = false;
308 memory->_writeable = false;
310 memory->_isSaneFD = sane ? 1 : 0;
311 memory->_wantReadType = (callBackTypes & 0x3);
312 memory->_reenableRead = memory->_wantReadType ? true : false;
313 memory->_readDisabled = false;
314 memory->_wantWrite = (callBackTypes & kCFSocketWriteCallBack) ? true : false;
315 memory->_reenableWrite = false;
316 memory->_writeDisabled = false;
317 memory->_wantConnect = (callBackTypes & kCFSocketConnectCallBack) ? true : false;
318 memory->_connectDisabled = false;
319 memory->_leaveErrors = false;
320 memory->_closeOnInvalidate = true;
321 memory->_connOriented = (SOCK_STREAM == socketType || SOCK_SEQPACKET == socketType);
322 memory->_connected = (memory->_wantReadType == kCFSocketAcceptCallBack || !memory->_connOriented) ? true : false;
325 memory->_runLoopCounter = 0;
326 memory->_address = NULL;
327 memory->_peerAddress = NULL;
328 memory->_context.info = NULL;
329 memory->_context.retain = NULL;
330 memory->_context.release = NULL;
331 memory->_context.copyDescription = NULL;
332 memory->_callout = callout;
333 if (NULL != context) {
334 objc_memmove_collectable(&memory->_context, context, sizeof(CFSocketContext));
335 memory->_context.info = context->retain ? (void *)context->retain(context->info) : context->info;
338 struct __shared_blob *shared = malloc(sizeof(struct __shared_blob));
339 shared->_rdsrc = NULL;
340 shared->_wrsrc = NULL;
341 shared->_source = NULL;
342 shared->_socket = ufd;
343 shared->_closeFD = true; // copy of _closeOnInvalidate
344 shared->_refCnt = 1; // one for the CFSocket
345 memory->_shared = shared;
347 if (memory->_wantReadType) {
348 dispatch_source_t dsrc = NULL;
350 dsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, ufd, 0, __sockQueue());
352 dsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, __sockQueue());
353 dispatch_source_set_timer(dsrc, dispatch_time(DISPATCH_TIME_NOW, 0), NSEC_PER_SEC / 2, NSEC_PER_SEC);
355 dispatch_block_t event_block = ^{
356 memory->_readable = true;
357 if (!memory->_rsuspended) {
358 dispatch_suspend(dsrc);
359 // CFLog(5, CFSTR("suspend %p due to read event block"), memory);
360 memory->_rsuspended = true;
362 if (shared->_source) {
363 CFRunLoopSourceSignal(shared->_source);
364 _CFRunLoopSourceWakeUpRunLoops(shared->_source);
367 dispatch_block_t cancel_block = ^{
368 shared->_rdsrc = NULL;
370 if (0 == shared->_refCnt) {
371 if (shared->_closeFD) {
372 // thoroughly stop anything else from using the fd
373 (void)shutdown(shared->_socket, SHUT_RDWR);
374 int nullfd = open("/dev/null", O_RDONLY);
375 dup2(nullfd, shared->_socket);
377 close(shared->_socket);
381 dispatch_release(dsrc);
383 dispatch_source_set_event_handler(dsrc, event_block);
384 dispatch_source_set_cancel_handler(dsrc, cancel_block);
385 shared->_rdsrc = dsrc;
387 if (memory->_wantWrite || memory->_wantConnect) {
388 dispatch_source_t dsrc = NULL;
390 dsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, ufd, 0, __sockQueue());
392 dsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, __sockQueue());
393 dispatch_source_set_timer(dsrc, dispatch_time(DISPATCH_TIME_NOW, 0), NSEC_PER_SEC / 2, NSEC_PER_SEC);
395 dispatch_block_t event_block = ^{
396 memory->_writeable = true;
397 if (!memory->_wsuspended) {
398 dispatch_suspend(dsrc);
399 // CFLog(5, CFSTR("suspend %p due to write event block"), memory);
400 memory->_wsuspended = true;
402 if (shared->_source) {
403 CFRunLoopSourceSignal(shared->_source);
404 _CFRunLoopSourceWakeUpRunLoops(shared->_source);
407 dispatch_block_t cancel_block = ^{
408 shared->_wrsrc = NULL;
410 if (0 == shared->_refCnt) {
411 if (shared->_closeFD) {
412 // thoroughly stop anything else from using the fd
413 (void)shutdown(shared->_socket, SHUT_RDWR);
414 int nullfd = open("/dev/null", O_RDONLY);
415 dup2(nullfd, shared->_socket);
417 close(shared->_socket);
421 dispatch_release(dsrc);
423 dispatch_source_set_event_handler(dsrc, event_block);
424 dispatch_source_set_cancel_handler(dsrc, cancel_block);
425 shared->_wrsrc = dsrc;
428 if (shared->_rdsrc) {
431 if (shared->_wrsrc) {
435 memory->_state = kCFSocketStateReady;
436 CFArrayAppendValue(__CFAllSockets, memory);
439 // CFLog(5, CFSTR("CFSocketCreateWithNative(): created socket %p with callbacks 0x%x"), sock, callBackTypes);
440 if (sock && !CFSocketIsValid(sock)) { // must do this outside lock to avoid deadlock
447 CFSocketNativeHandle CFSocketGetNative(CFSocketRef sock) {
448 CHECK_FOR_FORK_RET(INVALID_SOCKET);
449 __CFGenericValidateType(sock, CFSocketGetTypeID());
450 return sock->_shared ? sock->_shared->_socket : INVALID_SOCKET;
453 void CFSocketGetContext(CFSocketRef sock, CFSocketContext *context) {
454 __CFGenericValidateType(sock, CFSocketGetTypeID());
455 CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__);
456 objc_memmove_collectable(context, &sock->_context, sizeof(CFSocketContext));
459 CFDataRef CFSocketCopyAddress(CFSocketRef sock) {
460 CHECK_FOR_FORK_RET(NULL);
461 __CFGenericValidateType(sock, CFSocketGetTypeID());
462 __block CFDataRef result = NULL;
463 dispatch_sync(__sockQueue(), ^{
464 if (!sock->_address) {
465 if (!__CFSocketIsValid(sock)) return;
466 uint8_t name[MAX_SOCKADDR_LEN];
467 socklen_t namelen = sizeof(name);
468 int ret = getsockname(sock->_shared->_socket, (struct sockaddr *)name, (socklen_t *)&namelen);
469 if (0 == ret && 0 < namelen) {
470 sock->_address = CFDataCreate(CFGetAllocator(sock), name, namelen);
473 result = sock->_address ? (CFDataRef)CFRetain(sock->_address) : NULL;
478 CFDataRef CFSocketCopyPeerAddress(CFSocketRef sock) {
479 CHECK_FOR_FORK_RET(NULL);
480 __CFGenericValidateType(sock, CFSocketGetTypeID());
481 __block CFDataRef result = NULL;
482 dispatch_sync(__sockQueue(), ^{
483 if (!sock->_peerAddress) {
484 if (!__CFSocketIsValid(sock)) return;
485 uint8_t name[MAX_SOCKADDR_LEN];
486 socklen_t namelen = sizeof(name);
487 int ret = getpeername(sock->_shared->_socket, (struct sockaddr *)name, (socklen_t *)&namelen);
488 if (0 == ret && 0 < namelen) {
489 sock->_peerAddress = CFDataCreate(CFGetAllocator(sock), name, namelen);
492 result = sock->_peerAddress ? (CFDataRef)CFRetain(sock->_peerAddress) : NULL;
497 CFOptionFlags CFSocketGetSocketFlags(CFSocketRef sock) {
499 __CFGenericValidateType(sock, CFSocketGetTypeID());
500 __block CFOptionFlags flags = 0;
501 dispatch_sync(__sockQueue(), ^{
502 if (sock->_reenableRead) flags |= sock->_wantReadType; // flags are same as types here
503 if (sock->_reenableWrite) flags |= kCFSocketAutomaticallyReenableWriteCallBack;
504 if (sock->_leaveErrors) flags |= kCFSocketLeaveErrors;
505 if (sock->_closeOnInvalidate) flags |= kCFSocketCloseOnInvalidate;
510 void CFSocketSetSocketFlags(CFSocketRef sock, CFOptionFlags flags) {
512 // CFLog(5, CFSTR("CFSocketSetSocketFlags(%p, 0x%x) starting"), sock, flags);
513 __CFGenericValidateType(sock, CFSocketGetTypeID());
514 dispatch_sync(__sockQueue(), ^{
515 sock->_reenableRead = (sock->_wantReadType && ((flags & 0x3) == sock->_wantReadType)) ? true : false;
516 sock->_reenableWrite = (sock->_wantWrite && (flags & kCFSocketAutomaticallyReenableWriteCallBack)) ? true : false;
517 sock->_leaveErrors = (flags & kCFSocketLeaveErrors) ? true : false;
518 sock->_closeOnInvalidate = (flags & kCFSocketCloseOnInvalidate) ? true : false;
519 if (sock->_shared) sock->_shared->_closeFD = sock->_closeOnInvalidate;
521 // CFLog(5, CFSTR("CFSocketSetSocketFlags(%p, 0x%x) done"), sock, flags);
524 void CFSocketEnableCallBacks(CFSocketRef sock, CFOptionFlags callBackTypes) {
525 CHECK_FOR_FORK_RET();
526 __CFGenericValidateType(sock, CFSocketGetTypeID());
527 // CFLog(5, CFSTR("CFSocketEnableCallBacks(%p, 0x%x) starting"), sock, callBackTypes);
528 dispatch_sync(__sockQueue(), ^{
529 if (!__CFSocketIsValid(sock)) return;
530 if (sock->_wantReadType && (callBackTypes & 0x3) == sock->_wantReadType) {
531 if (sockfd_is_readable(sock->_shared->_socket)) {
532 sock->_readable = true;
533 // CFLog(5, CFSTR("CFSocketEnableCallBacks(%p, 0x%x) socket is readable"), sock, callBackTypes);
534 if (!sock->_rsuspended) {
535 dispatch_suspend(sock->_shared->_rdsrc);
536 sock->_rsuspended = true;
538 // If the source exists, but is now invalid, this next stuff is relatively harmless.
539 if (sock->_shared->_source) {
540 CFRunLoopSourceSignal(sock->_shared->_source);
541 _CFRunLoopSourceWakeUpRunLoops(sock->_shared->_source);
543 } else if (sock->_rsuspended && sock->_shared->_rdsrc) {
544 sock->_rsuspended = false;
545 dispatch_resume(sock->_shared->_rdsrc);
547 sock->_readDisabled = false;
549 if (sock->_wantWrite && (callBackTypes & kCFSocketWriteCallBack)) {
550 if (sockfd_is_writeable(sock->_shared->_socket)) {
551 sock->_writeable = true;
552 if (!sock->_wsuspended) {
553 dispatch_suspend(sock->_shared->_wrsrc);
554 sock->_wsuspended = true;
556 // If the source exists, but is now invalid, this next stuff is relatively harmless.
557 if (sock->_shared->_source) {
558 CFRunLoopSourceSignal(sock->_shared->_source);
559 _CFRunLoopSourceWakeUpRunLoops(sock->_shared->_source);
561 } else if (sock->_wsuspended && sock->_shared->_wrsrc) {
562 sock->_wsuspended = false;
563 dispatch_resume(sock->_shared->_wrsrc);
565 sock->_writeDisabled = false;
567 if (sock->_wantConnect && !sock->_connected && (callBackTypes & kCFSocketConnectCallBack)) {
568 if (sockfd_is_writeable(sock->_shared->_socket)) {
569 sock->_writeable = true;
570 if (!sock->_wsuspended) {
571 dispatch_suspend(sock->_shared->_wrsrc);
572 sock->_wsuspended = true;
574 // If the source exists, but is now invalid, this next stuff is relatively harmless.
575 if (sock->_shared->_source) {
576 CFRunLoopSourceSignal(sock->_shared->_source);
577 _CFRunLoopSourceWakeUpRunLoops(sock->_shared->_source);
579 } else if (sock->_wsuspended && sock->_shared->_wrsrc) {
580 sock->_wsuspended = false;
581 dispatch_resume(sock->_shared->_wrsrc);
583 sock->_connectDisabled = false;
586 // CFLog(5, CFSTR("CFSocketEnableCallBacks(%p, 0x%x) done"), sock, callBackTypes);
589 void CFSocketDisableCallBacks(CFSocketRef sock, CFOptionFlags callBackTypes) {
590 CHECK_FOR_FORK_RET();
591 __CFGenericValidateType(sock, CFSocketGetTypeID());
592 // CFLog(5, CFSTR("CFSocketDisableCallBacks(%p, 0x%x) starting"), sock, callBackTypes);
593 dispatch_sync(__sockQueue(), ^{
594 if (!__CFSocketIsValid(sock)) return;
595 if (sock->_wantReadType && (callBackTypes & 0x3) == sock->_wantReadType) {
596 if (!sock->_rsuspended && sock->_shared->_rdsrc) {
597 dispatch_suspend(sock->_shared->_rdsrc);
598 sock->_rsuspended = true;
600 sock->_readDisabled = true;
602 if (sock->_wantWrite && (callBackTypes & kCFSocketWriteCallBack)) {
603 if (!sock->_wsuspended && sock->_shared->_wrsrc) {
604 dispatch_suspend(sock->_shared->_wrsrc);
605 sock->_wsuspended = true;
607 sock->_writeDisabled = true;
609 if (sock->_wantConnect && !sock->_connected && (callBackTypes & kCFSocketConnectCallBack)) {
610 if (!sock->_wsuspended && sock->_shared->_wrsrc) {
611 dispatch_suspend(sock->_shared->_wrsrc);
612 sock->_wsuspended = true;
614 sock->_connectDisabled = true;
617 // CFLog(5, CFSTR("CFSocketDisableCallBacks(%p, 0x%x) done"), sock, callBackTypes);
620 void CFSocketInvalidate(CFSocketRef sock) {
621 CHECK_FOR_FORK_RET();
622 __CFGenericValidateType(sock, CFSocketGetTypeID());
624 // CFLog(5, CFSTR("CFSocketInvalidate(%p) starting"), sock);
625 __block CFRunLoopSourceRef source = NULL;
626 __block Boolean wasReady = false;
627 dispatch_sync(__sockQueue(), ^{
628 wasReady = (sock->_state == kCFSocketStateReady);
630 sock->_state = kCFSocketStateInvalidating;
632 for (CFIndex idx = 0, cnt = CFArrayGetCount(__CFAllSockets); idx < cnt; idx++) {
633 CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(__CFAllSockets, idx);
635 CFArrayRemoveValueAtIndex(__CFAllSockets, idx);
639 if (sock->_shared->_rdsrc) {
640 dispatch_source_cancel(sock->_shared->_rdsrc);
641 if (sock->_rsuspended) {
642 sock->_rsuspended = false;
643 dispatch_resume(sock->_shared->_rdsrc);
646 if (sock->_shared->_wrsrc) {
647 dispatch_source_cancel(sock->_shared->_wrsrc);
648 if (sock->_wsuspended) {
649 sock->_wsuspended = false;
650 dispatch_resume(sock->_shared->_wrsrc);
653 source = sock->_shared->_source;
654 sock->_shared->_source = NULL;
655 sock->_shared->_refCnt--;
656 if (0 == sock->_shared->_refCnt) {
657 if (sock->_shared->_closeFD) {
658 // thoroughly stop anything else from using the fd
659 (void)shutdown(sock->_shared->_socket, SHUT_RDWR);
660 int nullfd = open("/dev/null", O_RDONLY);
661 dup2(nullfd, sock->_shared->_socket);
663 close(sock->_shared->_socket);
667 sock->_shared = NULL;
671 if (NULL != source) {
672 CFRunLoopSourceInvalidate(source);
675 void *info = sock->_context.info;
676 sock->_context.info = NULL;
677 if (sock->_context.release) {
678 sock->_context.release(info);
680 sock->_state = kCFSocketStateInvalid;
683 // CFLog(5, CFSTR("CFSocketInvalidate(%p) done%s"), sock, wasReady ? " -- done on this thread" : "");
687 Boolean CFSocketIsValid(CFSocketRef sock) {
688 __CFGenericValidateType(sock, CFSocketGetTypeID());
689 if (!__CFSocketIsValid(sock)) return false;
691 int ret = sock->_shared ? fstat(sock->_shared->_socket, &statbuf) : -1;
693 CFSocketInvalidate(sock);
700 static void __CFSocketPerform(void *info) { // CFRunLoop should only call this on one thread at a time
701 CHECK_FOR_FORK_RET();
702 CFSocketRef sock = (CFSocketRef)info;
704 // CFLog(5, CFSTR("__CFSocketPerform(%p) starting '%@'"), sock, sock);
705 __block Boolean doRead = false, doWrite = false, doConnect = false, isValid = false;
706 __block int fd = INVALID_SOCKET;
707 __block SInt32 errorCode = 0;
708 __block int new_fd = INVALID_SOCKET;
709 __block CFDataRef address = NULL;
710 __block CFMutableDataRef data = NULL;
711 __block void *context_info = NULL;
712 __block void (*context_release)(const void *) = NULL;
713 dispatch_sync(__sockQueue(), ^{
714 isValid = __CFSocketIsValid(sock);
715 if (!isValid) return;
716 fd = sock->_shared->_socket;
717 doRead = sock->_readable && sock->_wantReadType && !sock->_readDisabled;
719 sock->_readable = false;
720 doRead = sockfd_is_readable(fd);
721 // if (!doRead) CFLog(5, CFSTR("__CFSocketPerform(%p) socket is not actually readable"), sock);
723 doWrite = sock->_writeable && sock->_wantWrite && !sock->_writeDisabled;
724 doConnect = sock->_writeable && sock->_wantConnect && !sock->_connectDisabled && !sock->_connected;
725 if (doWrite || doConnect) {
726 sock->_writeable = false;
727 if (doWrite) doWrite = sockfd_is_writeable(fd);
728 if (doConnect) doConnect = sockfd_is_writeable(fd);
730 if (!sock->_leaveErrors && (doWrite || doConnect)) { // not on read, for whatever reason
731 int errorSize = sizeof(errorCode);
732 int ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&errorCode, (socklen_t *)&errorSize);
733 if (0 != ret) errorCode = 0;
734 sock->_error = errorCode;
736 sock->_connected = true;
737 // CFLog(5, CFSTR("__CFSocketPerform(%p) doing %d %d %d"), sock, doRead, doWrite, doConnect);
739 switch (sock->_wantReadType) {
740 case kCFSocketReadCallBack:
742 case kCFSocketAcceptCallBack: {
743 uint8_t name[MAX_SOCKADDR_LEN];
744 socklen_t namelen = sizeof(name);
745 new_fd = accept(fd, (struct sockaddr *)name, (socklen_t *)&namelen);
746 if (INVALID_SOCKET != new_fd) {
747 address = CFDataCreate(CFGetAllocator(sock), name, namelen);
751 case kCFSocketDataCallBack: {
752 uint8_t name[MAX_SOCKADDR_LEN];
753 socklen_t namelen = sizeof(name);
755 int ret = ioctlsocket(fd, FIONREAD, &avail);
756 if (ret < 0 || avail < 256) avail = 256;
757 if ((1 << 20) < avail) avail = (1 << 20);
758 data = CFDataCreateMutable(CFGetAllocator(sock), 0);
759 CFDataSetLength(data, avail);
760 ssize_t len = recvfrom(fd, CFDataGetMutableBytePtr(data), avail, 0, (struct sockaddr *)name, (socklen_t *)&namelen);
761 CFIndex datalen = (len < 0) ? 0 : len;
762 CFDataSetLength(data, datalen);
764 address = CFDataCreate(CFGetAllocator(sock), name, namelen);
765 } else if (sock->_connOriented) {
766 // cannot call CFSocketCopyPeerAddress(), or deadlock
767 if (!sock->_peerAddress) {
768 uint8_t name[MAX_SOCKADDR_LEN];
769 socklen_t namelen = sizeof(name);
770 int ret = getpeername(sock->_shared->_socket, (struct sockaddr *)name, (socklen_t *)&namelen);
771 if (0 == ret && 0 < namelen) {
772 sock->_peerAddress = CFDataCreate(CFGetAllocator(sock), name, namelen);
775 address = sock->_peerAddress ? (CFDataRef)CFRetain(sock->_peerAddress) : NULL;
777 if (NULL == address) {
778 address = CFDataCreate(CFGetAllocator(sock), NULL, 0);
784 if (sock->_reenableRead) {
785 // CFLog(5, CFSTR("__CFSocketPerform(%p) reenabling read %d %p"), sock, sock->_rsuspended, sock->_shared->_rdsrc);
786 if (sock->_rsuspended && sock->_shared->_rdsrc) {
787 sock->_rsuspended = false;
788 dispatch_resume(sock->_shared->_rdsrc);
791 if (sock->_reenableWrite) {
792 if (sock->_wsuspended && sock->_shared->_wrsrc) {
793 sock->_wsuspended = false;
794 dispatch_resume(sock->_shared->_wrsrc);
797 if (sock->_context.retain && (doConnect || doRead || doWrite)) {
798 context_info = (void *)sock->_context.retain(sock->_context.info);
799 context_release = sock->_context.release;
801 context_info = sock->_context.info;
804 // CFLog(5, CFSTR("__CFSocketPerform(%p) isValid:%d, doRead:%d, doWrite:%d, doConnect:%d error:%d"), sock, isValid, doRead, doWrite, doConnect, errorCode);
805 if (!isValid || !(doConnect || doRead || doWrite)) return;
807 Boolean calledOut = false;
809 if (sock->_callout) sock->_callout(sock, kCFSocketConnectCallBack, NULL, (0 != errorCode) ? &errorCode : NULL, context_info);
812 if (doRead && (!calledOut || __CFSocketIsValid(sock))) {
813 switch (sock->_wantReadType) {
814 case kCFSocketReadCallBack:
815 if (sock->_callout) sock->_callout(sock, kCFSocketReadCallBack, NULL, NULL, context_info);
818 case kCFSocketAcceptCallBack:
819 if (INVALID_SOCKET != new_fd) {
820 if (sock->_callout) sock->_callout(sock, kCFSocketAcceptCallBack, address, &new_fd, context_info);
824 case kCFSocketDataCallBack:
825 if (sock->_callout) sock->_callout(sock, kCFSocketDataCallBack, address, data, context_info);
830 if (doWrite && (!calledOut || __CFSocketIsValid(sock))) {
831 if (0 == errorCode) {
832 if (sock->_callout) sock->_callout(sock, kCFSocketWriteCallBack, NULL, NULL, context_info);
837 if (data && 0 == CFDataGetLength(data)) CFSocketInvalidate(sock);
838 if (address) CFRelease(address);
839 if (data) CFRelease(data);
840 if (context_release) {
841 context_release(context_info);
844 CHECK_FOR_FORK_RET();
845 // CFLog(5, CFSTR("__CFSocketPerform(%p) done"), sock);
848 static void __CFSocketSchedule(void *info, CFRunLoopRef rl, CFStringRef mode) {
849 CFSocketRef sock = (CFSocketRef)info;
850 int32_t newVal = OSAtomicIncrement32Barrier(&sock->_runLoopCounter);
851 if (1 == newVal) { // on a transition from 0->1, the old code forced all desired callbacks enabled
852 CFOptionFlags types = sock->_wantReadType | (sock->_wantWrite ? kCFSocketWriteCallBack : 0) | (sock->_wantConnect ? kCFSocketConnectCallBack : 0);
853 CFSocketEnableCallBacks(sock, types);
858 static void __CFSocketCancel(void *info, CFRunLoopRef rl, CFStringRef mode) {
859 CFSocketRef sock = (CFSocketRef)info;
860 OSAtomicDecrement32Barrier(&sock->_runLoopCounter);
864 CFRunLoopSourceRef CFSocketCreateRunLoopSource(CFAllocatorRef allocator, CFSocketRef sock, CFIndex order) {
865 CHECK_FOR_FORK_RET(NULL);
866 __CFGenericValidateType(sock, CFSocketGetTypeID());
867 if (!CFSocketIsValid(sock)) return NULL;
868 __block CFRunLoopSourceRef result = NULL;
869 dispatch_sync(__sockQueue(), ^{
870 if (!__CFSocketIsValid(sock)) return;
871 if (NULL != sock->_shared->_source && !CFRunLoopSourceIsValid(sock->_shared->_source)) {
872 CFRelease(sock->_shared->_source);
873 sock->_shared->_source = NULL;
875 if (NULL == sock->_shared->_source) {
876 CFRunLoopSourceContext context;
878 context.info = (void *)sock;
879 context.retain = (const void *(*)(const void *))CFRetain;
880 context.release = (void (*)(const void *))CFRelease;
881 context.copyDescription = (CFStringRef (*)(const void *))__CFSocketCopyDescription;
882 context.equal = NULL;
884 context.schedule = __CFSocketSchedule;
885 context.cancel = __CFSocketCancel;
886 context.perform = __CFSocketPerform;
887 sock->_shared->_source = CFRunLoopSourceCreate(allocator, order, (CFRunLoopSourceContext *)&context);
888 if (sock->_shared->_source) {
889 if (sock->_wantReadType) {
890 if (sockfd_is_readable(sock->_shared->_socket)) {
891 sock->_readable = true;
892 if (!sock->_rsuspended) {
893 dispatch_suspend(sock->_shared->_rdsrc);
894 sock->_rsuspended = true;
896 if (sock->_shared->_source) {
897 CFRunLoopSourceSignal(sock->_shared->_source);
898 _CFRunLoopSourceWakeUpRunLoops(sock->_shared->_source);
900 } else if (sock->_rsuspended && sock->_shared->_rdsrc) {
901 sock->_rsuspended = false;
902 dispatch_resume(sock->_shared->_rdsrc);
905 if (sock->_wantWrite || (sock->_wantConnect && !sock->_connected)) {
906 if (sockfd_is_writeable(sock->_shared->_socket)) {
907 sock->_writeable = true;
908 if (!sock->_wsuspended) {
909 dispatch_suspend(sock->_shared->_wrsrc);
910 sock->_wsuspended = true;
912 if (sock->_shared->_source) {
913 CFRunLoopSourceSignal(sock->_shared->_source);
914 _CFRunLoopSourceWakeUpRunLoops(sock->_shared->_source);
916 } else if (sock->_wsuspended && sock->_shared->_wrsrc) {
917 sock->_wsuspended = false;
918 dispatch_resume(sock->_shared->_wrsrc);
923 result = sock->_shared->_source ? (CFRunLoopSourceRef)CFRetain(sock->_shared->_source) : NULL;
925 // CFLog(5, CFSTR("CFSocketCreateRunLoopSource(%p) => %p"), sock, result);
930 void __CFSocketSetSocketReadBufferAttrs(CFSocketRef s, CFTimeInterval timeout, CFIndex length) {
933 CFIndex __CFSocketRead(CFSocketRef s, UInt8* buffer, CFIndex length, int* error) {
935 int ret = read(CFSocketGetNative(s), buffer, length);
942 Boolean __CFSocketGetBytesAvailable(CFSocketRef s, CFIndex* ctBytesAvailable) {
944 int ret = ioctlsocket(CFSocketGetNative(s), FIONREAD, &bytesAvailable);
945 if (ret < 0) return false;
946 *ctBytesAvailable = (CFIndex)bytesAvailable;
951 #else /* not NEW_SOCKET */
954 #include <CoreFoundation/CFSocket.h>
955 #include <sys/types.h>
958 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
959 #include <sys/sysctl.h>
964 #include <CoreFoundation/CFArray.h>
965 #include <CoreFoundation/CFData.h>
966 #include <CoreFoundation/CFDictionary.h>
967 #include <CoreFoundation/CFRunLoop.h>
968 #include <CoreFoundation/CFString.h>
969 #include <CoreFoundation/CFPropertyList.h>
970 #include "CFInternal.h"
972 #if DEPLOYMENT_TARGET_WINDOWS
974 #define EINPROGRESS WSAEINPROGRESS
976 // redefine this to the winsock error in this file
978 #define EBADF WSAENOTSOCK
981 #define NFDBITS (sizeof(int32_t) * NBBY)
983 typedef int32_t fd_mask
;
984 typedef int socklen_t
;
986 #define gettimeofday _NS_gettimeofday
987 CF_PRIVATE
int _NS_gettimeofday(struct timeval
*tv
, struct timezone
*tz
);
989 // although this is only used for debug info, we define it for compatibility
990 #define timersub(tvp, uvp, vvp) \
992 (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
993 (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
994 if ((vvp)->tv_usec < 0) { \
996 (vvp)->tv_usec += 1000000; \
1001 #endif // DEPLOYMENT_TARGET_WINDOWS
1004 // On Mach we use a v0 RunLoopSource to make client callbacks. That source is signalled by a
1005 // separate SocketManager thread who uses select() to watch the sockets' fds.
1007 //#define LOG_CFSOCKET
1009 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1010 #define INVALID_SOCKET (CFSocketNativeHandle)(-1)
1011 #define closesocket(a) close((a))
1012 #define ioctlsocket(a,b,c) ioctl((a),(b),(c))
1015 CF_INLINE
int __CFSocketLastError(void) {
1016 #if DEPLOYMENT_TARGET_WINDOWS
1017 return WSAGetLastError();
1019 return thread_errno();
1023 CF_INLINE CFIndex
__CFSocketFdGetSize(CFDataRef fdSet
) {
1024 return NBBY
* CFDataGetLength(fdSet
);
1027 CF_INLINE Boolean
__CFSocketFdSet(CFSocketNativeHandle sock
, CFMutableDataRef fdSet
) {
1028 /* returns true if a change occurred, false otherwise */
1029 Boolean retval
= false;
1030 if (INVALID_SOCKET
!= sock
&& 0 <= sock
) {
1031 CFIndex numFds
= NBBY
* CFDataGetLength(fdSet
);
1033 if (sock
>= numFds
) {
1034 CFIndex oldSize
= numFds
/ NFDBITS
, newSize
= (sock
+ NFDBITS
) / NFDBITS
, changeInBytes
= (newSize
- oldSize
) * sizeof(fd_mask
);
1035 CFDataIncreaseLength(fdSet
, changeInBytes
);
1036 fds_bits
= (fd_mask
*)CFDataGetMutableBytePtr(fdSet
);
1037 memset(fds_bits
+ oldSize
, 0, changeInBytes
);
1039 fds_bits
= (fd_mask
*)CFDataGetMutableBytePtr(fdSet
);
1041 if (!FD_ISSET(sock
, (fd_set
*)fds_bits
)) {
1043 FD_SET(sock
, (fd_set
*)fds_bits
);
1050 #define MAX_SOCKADDR_LEN 256
1051 #define MAX_DATA_SIZE 65535
1052 #define MAX_CONNECTION_ORIENTED_DATA_SIZE 32768
1054 /* locks are to be acquired in the following order:
1055 (1) __CFAllSocketsLock
1056 (2) an individual CFSocket's lock
1057 (3) __CFActiveSocketsLock
1059 static CFLock_t __CFAllSocketsLock
= CFLockInit
; /* controls __CFAllSockets */
1060 static CFMutableDictionaryRef __CFAllSockets
= NULL
;
1061 static CFLock_t __CFActiveSocketsLock
= CFLockInit
; /* controls __CFRead/WriteSockets, __CFRead/WriteSocketsFds, __CFSocketManagerThread, and __CFSocketManagerIteration */
1062 static volatile UInt32 __CFSocketManagerIteration
= 0;
1063 static CFMutableArrayRef __CFWriteSockets
= NULL
;
1064 static CFMutableArrayRef __CFReadSockets
= NULL
;
1065 static CFMutableDataRef __CFWriteSocketsFds
= NULL
;
1066 static CFMutableDataRef __CFReadSocketsFds
= NULL
;
1067 static CFDataRef zeroLengthData
= NULL
;
1068 static Boolean __CFReadSocketsTimeoutInvalid
= true; /* rebuild the timeout value before calling select */
1070 static CFSocketNativeHandle __CFWakeupSocketPair
[2] = {INVALID_SOCKET
, INVALID_SOCKET
};
1071 static void *__CFSocketManagerThread
= NULL
;
1073 static void __CFSocketDoCallback(CFSocketRef s
, CFDataRef data
, CFDataRef address
, CFSocketNativeHandle sock
);
1076 CFRuntimeBase _base
;
1078 unsigned client
:8; // flags set by client (reenable, CloseOnInvalidate)
1079 unsigned disabled
:8; // flags marking disabled callbacks
1080 unsigned connected
:1; // Are we connected yet? (also true for connectionless sockets)
1081 unsigned writableHint
:1; // Did the polling the socket show it to be writable?
1082 unsigned closeSignaled
:1; // Have we seen FD_CLOSE? (only used on Win32)
1086 CFLock_t _writeLock
;
1087 CFSocketNativeHandle _socket
; /* immutable */
1091 CFDataRef _peerAddress
;
1092 SInt32 _socketSetCount
;
1093 CFRunLoopSourceRef _source0
; // v0 RLS, messaged from SocketMgr
1094 CFMutableArrayRef _runLoops
;
1095 CFSocketCallBack _callout
; /* immutable */
1096 CFSocketContext _context
; /* immutable */
1097 CFMutableArrayRef _dataQueue
; // queues to pass data from SocketMgr thread
1098 CFMutableArrayRef _addressQueue
;
1100 struct timeval _readBufferTimeout
;
1101 CFMutableDataRef _readBuffer
;
1102 CFIndex _bytesToBuffer
; /* is length of _readBuffer */
1103 CFIndex _bytesToBufferPos
; /* where the next _CFSocketRead starts from */
1104 CFIndex _bytesToBufferReadPos
; /* Where the buffer will next be read into (always after _bytesToBufferPos, but less than _bytesToBuffer) */
1106 int _bufferedReadError
;
1108 CFMutableDataRef _leftoverBytes
;
1110 // <rdar://problem/17849895>
1111 // If the timeout is set on the CFSocketRef but we never get select() timeout
1112 // because we always have some network events so select never times out (e.g. while having a large download).
1113 // We need to notify any waiting buffered read clients if there is data available without relying on select timing out.
1114 struct timeval _readBufferTimeoutNotificationTime
;
1115 Boolean _hitTheTimeout
;
1118 /* Bit 6 in the base reserved bits is used for write-signalled state (mutable) */
1119 /* Bit 5 in the base reserved bits is used for read-signalled state (mutable) */
1120 /* Bit 4 in the base reserved bits is used for invalid state (mutable) */
1121 /* Bits 0-3 in the base reserved bits are used for callback types (immutable) */
1122 /* Of this, bits 0-1 are used for the read callback type. */
1124 CF_INLINE Boolean
__CFSocketIsWriteSignalled(CFSocketRef s
) {
1125 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 6, 6);
1128 CF_INLINE
void __CFSocketSetWriteSignalled(CFSocketRef s
) {
1129 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 6, 6, 1);
1132 CF_INLINE
void __CFSocketUnsetWriteSignalled(CFSocketRef s
) {
1133 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 6, 6, 0);
1136 CF_INLINE Boolean
__CFSocketIsReadSignalled(CFSocketRef s
) {
1137 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 5, 5);
1140 CF_INLINE
void __CFSocketSetReadSignalled(CFSocketRef s
) {
1141 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 5, 5, 1);
1144 CF_INLINE
void __CFSocketUnsetReadSignalled(CFSocketRef s
) {
1145 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 5, 5, 0);
1148 CF_INLINE Boolean
__CFSocketIsValid(CFSocketRef s
) {
1149 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 4, 4);
1152 CF_INLINE
void __CFSocketSetValid(CFSocketRef s
) {
1153 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 4, 4, 1);
1156 CF_INLINE
void __CFSocketUnsetValid(CFSocketRef s
) {
1157 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 4, 4, 0);
1160 CF_INLINE
uint8_t __CFSocketCallBackTypes(CFSocketRef s
) {
1161 return (uint8_t)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 3, 0);
1164 CF_INLINE
uint8_t __CFSocketReadCallBackType(CFSocketRef s
) {
1165 return (uint8_t)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 1, 0);
1168 CF_INLINE
void __CFSocketSetCallBackTypes(CFSocketRef s
, uint8_t types
) {
1169 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 3, 0, types
& 0xF);
1172 CF_INLINE
void __CFSocketLock(CFSocketRef s
) {
1173 __CFLock(&(s
->_lock
));
1176 CF_INLINE
void __CFSocketUnlock(CFSocketRef s
) {
1177 __CFUnlock(&(s
->_lock
));
1180 CF_INLINE Boolean
__CFSocketIsConnectionOriented(CFSocketRef s
) {
1181 return (SOCK_STREAM
== s
->_socketType
|| SOCK_SEQPACKET
== s
->_socketType
);
1184 CF_INLINE Boolean
__CFSocketIsScheduled(CFSocketRef s
) {
1185 return (s
->_socketSetCount
> 0);
1188 CF_INLINE
void __CFSocketEstablishAddress(CFSocketRef s
) {
1189 /* socket should already be locked */
1190 uint8_t name
[MAX_SOCKADDR_LEN
];
1191 int namelen
= sizeof(name
);
1192 if (__CFSocketIsValid(s
) && NULL
== s
->_address
&& INVALID_SOCKET
!= s
->_socket
&& 0 == getsockname(s
->_socket
, (struct sockaddr
*)name
, (socklen_t
*)&namelen
) && NULL
!= name
&& 0 < namelen
) {
1193 s
->_address
= CFDataCreate(CFGetAllocator(s
), name
, namelen
);
1197 CF_INLINE
void __CFSocketEstablishPeerAddress(CFSocketRef s
) {
1198 /* socket should already be locked */
1199 uint8_t name
[MAX_SOCKADDR_LEN
];
1200 int namelen
= sizeof(name
);
1201 if (__CFSocketIsValid(s
) && NULL
== s
->_peerAddress
&& INVALID_SOCKET
!= s
->_socket
&& 0 == getpeername(s
->_socket
, (struct sockaddr
*)name
, (socklen_t
*)&namelen
) && NULL
!= name
&& 0 < namelen
) {
1202 s
->_peerAddress
= CFDataCreate(CFGetAllocator(s
), name
, namelen
);
1206 static Boolean
__CFNativeSocketIsValid(CFSocketNativeHandle sock
) {
1207 #if DEPLOYMENT_TARGET_WINDOWS
1208 SInt32 errorCode
= 0;
1209 int errorSize
= sizeof(errorCode
);
1210 return !(0 != getsockopt(sock
, SOL_SOCKET
, SO_ERROR
, (char *)&errorCode
, &errorSize
) && __CFSocketLastError() == WSAENOTSOCK
);
1212 SInt32 flags
= fcntl(sock
, F_GETFL
, 0);
1213 return !(0 > flags
&& EBADF
== __CFSocketLastError());
1217 CF_INLINE Boolean
__CFSocketFdClr(CFSocketNativeHandle sock
, CFMutableDataRef fdSet
) {
1218 /* returns true if a change occurred, false otherwise */
1219 Boolean retval
= false;
1220 if (INVALID_SOCKET
!= sock
&& 0 <= sock
) {
1221 CFIndex numFds
= NBBY
* CFDataGetLength(fdSet
);
1223 if (sock
< numFds
) {
1224 fds_bits
= (fd_mask
*)CFDataGetMutableBytePtr(fdSet
);
1225 if (FD_ISSET(sock
, (fd_set
*)fds_bits
)) {
1227 FD_CLR(sock
, (fd_set
*)fds_bits
);
1234 static SInt32
__CFSocketCreateWakeupSocketPair(void) {
1235 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1238 error
= socketpair(PF_LOCAL
, SOCK_DGRAM
, 0, __CFWakeupSocketPair
);
1239 if (0 <= error
) error
= fcntl(__CFWakeupSocketPair
[0], F_SETFD
, FD_CLOEXEC
);
1240 if (0 <= error
) error
= fcntl(__CFWakeupSocketPair
[1], F_SETFD
, FD_CLOEXEC
);
1242 closesocket(__CFWakeupSocketPair
[0]);
1243 closesocket(__CFWakeupSocketPair
[1]);
1244 __CFWakeupSocketPair
[0] = INVALID_SOCKET
;
1245 __CFWakeupSocketPair
[1] = INVALID_SOCKET
;
1250 struct sockaddr_in address
[2];
1251 int namelen
= sizeof(struct sockaddr_in
);
1252 for (i
= 0; i
< 2; i
++) {
1253 __CFWakeupSocketPair
[i
] = socket(PF_INET
, SOCK_DGRAM
, 0);
1254 memset(&(address
[i
]), 0, sizeof(struct sockaddr_in
));
1255 address
[i
].sin_family
= AF_INET
;
1256 address
[i
].sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
1257 if (0 <= error
) error
= bind(__CFWakeupSocketPair
[i
], (struct sockaddr
*)&(address
[i
]), sizeof(struct sockaddr_in
));
1258 if (0 <= error
) error
= getsockname(__CFWakeupSocketPair
[i
], (struct sockaddr
*)&(address
[i
]), &namelen
);
1259 if (sizeof(struct sockaddr_in
) != namelen
) error
= -1;
1261 if (0 <= error
) error
= connect(__CFWakeupSocketPair
[0], (struct sockaddr
*)&(address
[1]), sizeof(struct sockaddr_in
));
1262 if (0 <= error
) error
= connect(__CFWakeupSocketPair
[1], (struct sockaddr
*)&(address
[0]), sizeof(struct sockaddr_in
));
1264 closesocket(__CFWakeupSocketPair
[0]);
1265 closesocket(__CFWakeupSocketPair
[1]);
1266 __CFWakeupSocketPair
[0] = INVALID_SOCKET
;
1267 __CFWakeupSocketPair
[1] = INVALID_SOCKET
;
1270 #if defined(LOG_CFSOCKET)
1271 fprintf(stdout
, "wakeup socket pair is %d / %d\n", __CFWakeupSocketPair
[0], __CFWakeupSocketPair
[1]);
1277 // Version 0 RunLoopSources set a mask in an FD set to control what socket activity we hear about.
1278 // Changes to the master fs_sets occur via these 4 functions.
1279 CF_INLINE Boolean
__CFSocketSetFDForRead(CFSocketRef s
) {
1280 __CFReadSocketsTimeoutInvalid
= true;
1281 Boolean b
= __CFSocketFdSet(s
->_socket
, __CFReadSocketsFds
);
1282 if (b
&& INVALID_SOCKET
!= __CFWakeupSocketPair
[0]) {
1284 send(__CFWakeupSocketPair
[0], (const char *)&c
, sizeof(c
), 0);
1289 CF_INLINE Boolean
__CFSocketClearFDForRead(CFSocketRef s
) {
1290 __CFReadSocketsTimeoutInvalid
= true;
1291 Boolean b
= __CFSocketFdClr(s
->_socket
, __CFReadSocketsFds
);
1292 if (b
&& INVALID_SOCKET
!= __CFWakeupSocketPair
[0]) {
1294 send(__CFWakeupSocketPair
[0], (const char *)&c
, sizeof(c
), 0);
1299 CF_INLINE Boolean
__CFSocketSetFDForWrite(CFSocketRef s
) {
1300 // CFLog(5, CFSTR("__CFSocketSetFDForWrite(%p)"), s);
1301 Boolean b
= __CFSocketFdSet(s
->_socket
, __CFWriteSocketsFds
);
1302 if (b
&& INVALID_SOCKET
!= __CFWakeupSocketPair
[0]) {
1304 send(__CFWakeupSocketPair
[0], (const char *)&c
, sizeof(c
), 0);
1309 CF_INLINE Boolean
__CFSocketClearFDForWrite(CFSocketRef s
) {
1310 // CFLog(5, CFSTR("__CFSocketClearFDForWrite(%p)"), s);
1311 Boolean b
= __CFSocketFdClr(s
->_socket
, __CFWriteSocketsFds
);
1312 if (b
&& INVALID_SOCKET
!= __CFWakeupSocketPair
[0]) {
1314 send(__CFWakeupSocketPair
[0], (const char *)&c
, sizeof(c
), 0);
1319 #if DEPLOYMENT_TARGET_WINDOWS
1320 static Boolean WinSockUsed
= FALSE
;
1322 static void __CFSocketInitializeWinSock_Guts(void) {
1325 WORD versionRequested
= MAKEWORD(2, 2);
1327 int errorStatus
= WSAStartup(versionRequested
, &wsaData
);
1328 if (errorStatus
!= 0 || LOBYTE(wsaData
.wVersion
) != LOBYTE(versionRequested
) || HIBYTE(wsaData
.wVersion
) != HIBYTE(versionRequested
)) {
1330 CFLog(kCFLogLevelWarning
, CFSTR("*** Could not initialize WinSock subsystem!!!"));
1335 CF_EXPORT
void __CFSocketInitializeWinSock(void) {
1336 __CFLock(&__CFActiveSocketsLock
);
1337 __CFSocketInitializeWinSock_Guts();
1338 __CFUnlock(&__CFActiveSocketsLock
);
1341 CF_PRIVATE
void __CFSocketCleanup(void) {
1342 if (INVALID_SOCKET
!= __CFWakeupSocketPair
[0]) {
1343 closesocket(__CFWakeupSocketPair
[0]);
1344 __CFWakeupSocketPair
[0] = INVALID_SOCKET
;
1346 if (INVALID_SOCKET
!= __CFWakeupSocketPair
[1]) {
1347 closesocket(__CFWakeupSocketPair
[1]);
1348 __CFWakeupSocketPair
[1] = INVALID_SOCKET
;
1351 // 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
1358 // CFNetwork needs to call this, especially for Win32 to get WSAStartup
1359 static void __CFSocketInitializeSockets(void) {
1360 __CFWriteSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
);
1361 __CFReadSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
);
1362 __CFWriteSocketsFds
= CFDataCreateMutable(kCFAllocatorSystemDefault
, 0);
1363 __CFReadSocketsFds
= CFDataCreateMutable(kCFAllocatorSystemDefault
, 0);
1364 zeroLengthData
= CFDataCreateMutable(kCFAllocatorSystemDefault
, 0);
1365 #if DEPLOYMENT_TARGET_WINDOWS
1366 __CFSocketInitializeWinSock_Guts();
1368 if (0 > __CFSocketCreateWakeupSocketPair()) {
1369 CFLog(kCFLogLevelWarning
, CFSTR("*** Could not create wakeup socket pair for CFSocket!!!"));
1372 /* wakeup sockets must be non-blocking */
1373 ioctlsocket(__CFWakeupSocketPair
[0], FIONBIO
, (u_long
*)&yes
);
1374 ioctlsocket(__CFWakeupSocketPair
[1], FIONBIO
, (u_long
*)&yes
);
1375 __CFSocketFdSet(__CFWakeupSocketPair
[1], __CFReadSocketsFds
);
1379 static CFRunLoopRef
__CFSocketCopyRunLoopToWakeUp(CFRunLoopSourceRef src
, CFMutableArrayRef runLoops
) {
1380 if (!src
) return NULL
;
1381 CFRunLoopRef rl
= NULL
;
1382 SInt32 idx
, cnt
= CFArrayGetCount(runLoops
);
1384 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(runLoops
, 0);
1385 for (idx
= 1; NULL
!= rl
&& idx
< cnt
; idx
++) {
1386 CFRunLoopRef value
= (CFRunLoopRef
)CFArrayGetValueAtIndex(runLoops
, idx
);
1387 if (value
!= rl
) rl
= NULL
;
1389 if (NULL
== rl
) { /* more than one different rl, so we must pick one */
1390 /* ideally, this would be a run loop which isn't also in a
1391 * signaled state for this or another source, but that's tricky;
1392 * we pick one that is running in an appropriate mode for this
1393 * source, and from those if possible one that is waiting; then
1394 * we move this run loop to the end of the list to scramble them
1395 * a bit, and always search from the front */
1396 Boolean foundIt
= false, foundBackup
= false;
1397 SInt32 foundIdx
= 0;
1398 for (idx
= 0; !foundIt
&& idx
< cnt
; idx
++) {
1399 CFRunLoopRef value
= (CFRunLoopRef
)CFArrayGetValueAtIndex(runLoops
, idx
);
1400 CFStringRef currentMode
= CFRunLoopCopyCurrentMode(value
);
1401 if (NULL
!= currentMode
) {
1402 if (CFRunLoopContainsSource(value
, src
, currentMode
)) {
1403 if (CFRunLoopIsWaiting(value
)) {
1406 } else if (!foundBackup
) {
1411 CFRelease(currentMode
);
1414 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(runLoops
, foundIdx
);
1416 CFArrayRemoveValueAtIndex(runLoops
, foundIdx
);
1417 CFArrayAppendValue(runLoops
, rl
);
1425 // If callBackNow, we immediately do client callbacks, else we have to signal a v0 RunLoopSource so the
1426 // callbacks can happen in another thread.
1427 static void __CFSocketHandleWrite(CFSocketRef s
, Boolean callBackNow
) {
1428 SInt32 errorCode
= 0;
1429 int errorSize
= sizeof(errorCode
);
1430 CFOptionFlags writeCallBacksAvailable
;
1432 if (!CFSocketIsValid(s
)) return;
1433 if (0 != (s
->_f
.client
& kCFSocketLeaveErrors
) || 0 != getsockopt(s
->_socket
, SOL_SOCKET
, SO_ERROR
, (char *)&errorCode
, (socklen_t
*)&errorSize
)) errorCode
= 0;
1434 // cast for WinSock bad API
1435 #if defined(LOG_CFSOCKET)
1436 if (errorCode
) fprintf(stdout
, "error %ld on socket %d\n", (long)errorCode
, s
->_socket
);
1439 writeCallBacksAvailable
= __CFSocketCallBackTypes(s
) & (kCFSocketWriteCallBack
| kCFSocketConnectCallBack
);
1440 if ((s
->_f
.client
& kCFSocketConnectCallBack
) != 0) writeCallBacksAvailable
&= ~kCFSocketConnectCallBack
;
1441 if (!__CFSocketIsValid(s
) || ((s
->_f
.disabled
& writeCallBacksAvailable
) == writeCallBacksAvailable
)) {
1442 __CFSocketUnlock(s
);
1445 s
->_errorCode
= errorCode
;
1446 __CFSocketSetWriteSignalled(s
);
1447 // CFLog(5, CFSTR("__CFSocketHandleWrite() signalling write on socket %p"), s);
1448 #if defined(LOG_CFSOCKET)
1449 fprintf(stdout
, "write signaling source for socket %d\n", s
->_socket
);
1452 __CFSocketDoCallback(s
, NULL
, NULL
, 0);
1454 CFRunLoopSourceSignal(s
->_source0
);
1455 CFMutableArrayRef runLoopsOrig
= (CFMutableArrayRef
)CFRetain(s
->_runLoops
);
1456 CFMutableArrayRef runLoopsCopy
= CFArrayCreateMutableCopy(kCFAllocatorSystemDefault
, 0, s
->_runLoops
);
1457 CFRunLoopSourceRef source0
= s
->_source0
;
1458 if (NULL
!= source0
&& !CFRunLoopSourceIsValid(source0
)) {
1461 if (source0
) CFRetain(source0
);
1462 __CFSocketUnlock(s
);
1463 CFRunLoopRef rl
= __CFSocketCopyRunLoopToWakeUp(source0
, runLoopsCopy
);
1464 if (source0
) CFRelease(source0
);
1466 CFRunLoopWakeUp(rl
);
1470 if (runLoopsOrig
== s
->_runLoops
) {
1471 s
->_runLoops
= runLoopsCopy
;
1472 runLoopsCopy
= NULL
;
1473 CFRelease(runLoopsOrig
);
1475 __CFSocketUnlock(s
);
1476 CFRelease(runLoopsOrig
);
1477 if (runLoopsCopy
) CFRelease(runLoopsCopy
);
1482 #if defined(LOG_CFSOCKET)
1484 static CFStringRef
someAddrToString(CFAllocatorRef alloc
, int (*fun
) (int, struct sockaddr
*, socklen_t
*), const char* name
, CFSocketNativeHandle s
)
1486 CFStringRef resultString
= NULL
;
1489 struct sockaddr_in sa4b
;
1490 struct sockaddr_in6 sa6b
;
1491 UInt8 static_buffer
[SOCK_MAXADDRLEN
];
1493 socklen_t addrlen
= sizeof(u
.static_buffer
);
1495 uint16_t* pPort
= NULL
;
1498 if ((*fun
) (s
, &u
.sa
, &addrlen
) != 0)
1499 snprintf(buffer
, sizeof(buffer
), "error %d resolving %s address for socket %d", errno
, name
, s
);
1503 switch (u
.sa
.sa_family
) {
1505 pAddr
= &u
.sa4b
.sin_addr
;
1506 pPort
= &u
.sa4b
.sin_port
;
1509 pAddr
= &u
.sa6b
.sin6_addr
;
1510 pPort
= &u
.sa6b
.sin6_port
;
1514 if (pAddr
== NULL
|| inet_ntop(u
.sa
.sa_family
, pAddr
, buffer
, sizeof(buffer
)) == NULL
)
1515 snprintf(buffer
, sizeof(buffer
), "[error %d converting %s address for socket %d]", pAddr
!= NULL
? errno
: EBADF
, name
, s
);
1518 resultString
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%s:%d"), buffer
, htons(*pPort
));
1520 resultString
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%s"), buffer
);
1522 return resultString
;
1525 CFStringRef
copyPeerAddress(CFAllocatorRef alloc
, CFSocketNativeHandle s
)
1527 return someAddrToString(alloc
, getpeername
, "peer", s
);
1530 CFStringRef
copyLocalAddress(CFAllocatorRef alloc
, CFSocketNativeHandle s
)
1532 return someAddrToString(alloc
, getsockname
, "local", s
);
1537 static void __CFSocketHandleRead(CFSocketRef s
, Boolean causedByTimeout
)
1539 CFDataRef data
= NULL
, address
= NULL
;
1540 CFSocketNativeHandle sock
= INVALID_SOCKET
;
1541 if (!CFSocketIsValid(s
)) return;
1542 if (__CFSocketReadCallBackType(s
) == kCFSocketDataCallBack
) {
1543 uint8_t bufferArray
[MAX_CONNECTION_ORIENTED_DATA_SIZE
], *buffer
;
1544 uint8_t name
[MAX_SOCKADDR_LEN
];
1545 int namelen
= sizeof(name
);
1547 if (__CFSocketIsConnectionOriented(s
)) {
1548 buffer
= bufferArray
;
1549 recvlen
= recvfrom(s
->_socket
, (char *)buffer
, MAX_CONNECTION_ORIENTED_DATA_SIZE
, 0, (struct sockaddr
*)name
, (socklen_t
*)&namelen
);
1551 buffer
= (uint8_t *)malloc(MAX_DATA_SIZE
);
1552 if (buffer
) recvlen
= recvfrom(s
->_socket
, (char *)buffer
, MAX_DATA_SIZE
, 0, (struct sockaddr
*)name
, (socklen_t
*)&namelen
);
1554 #if defined(LOG_CFSOCKET)
1555 fprintf(stdout
, "read %ld bytes on socket %d\n", (long)recvlen
, s
->_socket
);
1558 //??? should return error if <0
1559 /* zero-length data is the signal for perform to invalidate */
1560 data
= (CFDataRef
)CFRetain(zeroLengthData
);
1562 data
= CFDataCreate(CFGetAllocator(s
), buffer
, recvlen
);
1564 if (buffer
&& buffer
!= bufferArray
) free(buffer
);
1566 if (!__CFSocketIsValid(s
)) {
1568 __CFSocketUnlock(s
);
1571 __CFSocketSetReadSignalled(s
);
1572 if (NULL
!= name
&& 0 < namelen
) {
1573 //??? possible optimizations: uniquing; storing last value
1574 address
= CFDataCreate(CFGetAllocator(s
), name
, namelen
);
1575 } else if (__CFSocketIsConnectionOriented(s
)) {
1576 if (NULL
== s
->_peerAddress
) __CFSocketEstablishPeerAddress(s
);
1577 if (NULL
!= s
->_peerAddress
) address
= (CFDataRef
)CFRetain(s
->_peerAddress
);
1579 if (NULL
== address
) {
1580 address
= (CFDataRef
)CFRetain(zeroLengthData
);
1582 if (NULL
== s
->_dataQueue
) {
1583 s
->_dataQueue
= CFArrayCreateMutable(CFGetAllocator(s
), 0, &kCFTypeArrayCallBacks
);
1585 if (NULL
== s
->_addressQueue
) {
1586 s
->_addressQueue
= CFArrayCreateMutable(CFGetAllocator(s
), 0, &kCFTypeArrayCallBacks
);
1588 CFArrayAppendValue(s
->_dataQueue
, data
);
1590 CFArrayAppendValue(s
->_addressQueue
, address
);
1593 && (s
->_f
.client
& kCFSocketDataCallBack
) != 0 && (s
->_f
.disabled
& kCFSocketDataCallBack
) == 0
1594 && __CFSocketIsScheduled(s
)
1596 __CFLock(&__CFActiveSocketsLock
);
1597 /* restore socket to fds */
1598 __CFSocketSetFDForRead(s
);
1599 __CFUnlock(&__CFActiveSocketsLock
);
1601 } else if (__CFSocketReadCallBackType(s
) == kCFSocketAcceptCallBack
) {
1602 uint8_t name
[MAX_SOCKADDR_LEN
];
1603 int namelen
= sizeof(name
);
1604 sock
= accept(s
->_socket
, (struct sockaddr
*)name
, (socklen_t
*)&namelen
);
1605 if (INVALID_SOCKET
== sock
) {
1606 //??? should return error
1609 if (NULL
!= name
&& 0 < namelen
) {
1610 address
= CFDataCreate(CFGetAllocator(s
), name
, namelen
);
1612 address
= (CFDataRef
)CFRetain(zeroLengthData
);
1615 if (!__CFSocketIsValid(s
)) {
1618 __CFSocketUnlock(s
);
1621 __CFSocketSetReadSignalled(s
);
1622 if (NULL
== s
->_dataQueue
) {
1623 s
->_dataQueue
= CFArrayCreateMutable(CFGetAllocator(s
), 0, NULL
);
1625 if (NULL
== s
->_addressQueue
) {
1626 s
->_addressQueue
= CFArrayCreateMutable(CFGetAllocator(s
), 0, &kCFTypeArrayCallBacks
);
1628 CFArrayAppendValue(s
->_dataQueue
, (void *)(uintptr_t)sock
);
1629 CFArrayAppendValue(s
->_addressQueue
, address
);
1631 if ((s
->_f
.client
& kCFSocketAcceptCallBack
) != 0 && (s
->_f
.disabled
& kCFSocketAcceptCallBack
) == 0
1632 && __CFSocketIsScheduled(s
)
1634 __CFLock(&__CFActiveSocketsLock
);
1635 /* restore socket to fds */
1636 __CFSocketSetFDForRead(s
);
1637 __CFUnlock(&__CFActiveSocketsLock
);
1641 if (!__CFSocketIsValid(s
) || (s
->_f
.disabled
& kCFSocketReadCallBack
) != 0) {
1642 __CFSocketUnlock(s
);
1646 if (causedByTimeout
) {
1647 #if defined(LOG_CFSOCKET)
1648 fprintf(stdout
, "TIMEOUT RECEIVED - WILL SIGNAL IMMEDIATELY TO FLUSH (%ld buffered)\n", s
->_bytesToBufferPos
);
1650 /* we've got a timeout, but no bytes read, and we don't have any bytes to send. Ignore the timeout. */
1651 if (s
->_bytesToBufferPos
== 0 && s
->_leftoverBytes
== NULL
) {
1652 #if defined(LOG_CFSOCKET)
1653 fprintf(stdout
, "TIMEOUT - but no bytes, restoring to active set\n");
1656 // Clear the timeout notification time if there is no prefetched data left
1657 timerclear(&s
->_readBufferTimeoutNotificationTime
);
1659 __CFLock(&__CFActiveSocketsLock
);
1660 /* restore socket to fds */
1661 __CFSocketSetFDForRead(s
);
1662 __CFUnlock(&__CFActiveSocketsLock
);
1663 __CFSocketUnlock(s
);
1666 } else if (s
->_bytesToBuffer
!= 0 && ! s
->_atEOF
) {
1669 CFIndex ctRemaining
= s
->_bytesToBuffer
- s
->_bytesToBufferPos
;
1671 /* if our buffer has room, we go ahead and buffer */
1672 if (ctRemaining
> 0) {
1673 base
= CFDataGetMutableBytePtr(s
->_readBuffer
);
1675 struct timeval timeBeforeRead
= { 0 };
1676 gettimeofday(&timeBeforeRead
, NULL
);
1678 struct timeval deadlineTime
= { 0 };
1679 timeradd(&timeBeforeRead
, &s
->_readBufferTimeout
, &deadlineTime
);
1681 struct timeval timeAfterRead
= { 0 };
1684 ctRead
= read(CFSocketGetNative(s
), &base
[s
->_bytesToBufferPos
], ctRemaining
);
1690 if (errno
!= EAGAIN
) {
1694 gettimeofday(&timeAfterRead
, NULL
);
1696 if (timercmp(&timeAfterRead
, &deadlineTime
, >)) {
1697 #if defined(LOG_CFSOCKET)
1698 CFSocketNativeHandle fd
= CFSocketGetNative(s
);
1699 CFStringRef peerName
= copyPeerAddress(kCFAllocatorDefault
, fd
);
1700 CFStringRef localName
= copyLocalAddress(kCFAllocatorDefault
, fd
);
1701 CFLog(kCFLogLevelCritical
, CFSTR("ERROR: Buffered read of %llu bytes failed for fd %d (socket valid? %d fd valid? %d %@ => %@)"), ctRemaining
, fd
, __CFSocketIsValid(s
), __CFNativeSocketIsValid(fd
), localName
, peerName
);
1703 CFRelease(peerName
);
1705 CFRelease(localName
);
1713 s
->_bufferedReadError
= errno
;
1715 #if defined(LOG_CFSOCKET)
1716 fprintf(stderr
, "BUFFERED READ GOT ERROR %d\n", errno
);
1721 #if defined(LOG_CFSOCKET)
1722 fprintf(stdout
, "DONE READING (EOF) - GOING TO SIGNAL\n");
1728 s
->_bytesToBufferPos
+= ctRead
;
1729 if (s
->_bytesToBuffer
!= s
->_bytesToBufferPos
) {
1731 // Update the timeout notification time
1732 struct timeval timeNow
= { 0 };
1733 gettimeofday(&timeNow
, NULL
);
1734 timeradd(&timeNow
, &s
->_readBufferTimeout
, &s
->_readBufferTimeoutNotificationTime
);
1735 #if defined(LOG_CFSOCKET)
1736 fprintf(stdout
, "READ %ld - need %ld MORE - GOING BACK FOR MORE\n", ctRead
, s
->_bytesToBuffer
- s
->_bytesToBufferPos
);
1738 __CFLock(&__CFActiveSocketsLock
);
1739 /* restore socket to fds */
1740 __CFSocketSetFDForRead(s
);
1741 __CFUnlock(&__CFActiveSocketsLock
);
1742 __CFSocketUnlock(s
);
1745 // Clear the timeout notification time if the buffer is full
1746 timerclear(&s
->_readBufferTimeoutNotificationTime
);
1747 #if defined(LOG_CFSOCKET)
1748 fprintf(stdout
, "DONE READING (read %ld bytes) - GOING TO SIGNAL\n", ctRead
);
1755 __CFSocketSetReadSignalled(s
);
1757 #if defined(LOG_CFSOCKET)
1758 fprintf(stdout
, "read signaling source for socket %d\n", s
->_socket
);
1760 CFRunLoopSourceSignal(s
->_source0
);
1761 CFMutableArrayRef runLoopsOrig
= (CFMutableArrayRef
)CFRetain(s
->_runLoops
);
1762 CFMutableArrayRef runLoopsCopy
= CFArrayCreateMutableCopy(kCFAllocatorSystemDefault
, 0, s
->_runLoops
);
1763 CFRunLoopSourceRef source0
= s
->_source0
;
1764 if (NULL
!= source0
&& !CFRunLoopSourceIsValid(source0
)) {
1767 if (source0
) CFRetain(source0
);
1768 __CFSocketUnlock(s
);
1769 CFRunLoopRef rl
= __CFSocketCopyRunLoopToWakeUp(source0
, runLoopsCopy
);
1770 if (source0
) CFRelease(source0
);
1772 CFRunLoopWakeUp(rl
);
1776 if (runLoopsOrig
== s
->_runLoops
) {
1777 s
->_runLoops
= runLoopsCopy
;
1778 runLoopsCopy
= NULL
;
1779 CFRelease(runLoopsOrig
);
1781 __CFSocketUnlock(s
);
1782 CFRelease(runLoopsOrig
);
1783 if (runLoopsCopy
) CFRelease(runLoopsCopy
);
1786 static struct timeval
* intervalToTimeval(CFTimeInterval timeout
, struct timeval
* tv
)
1791 tv
->tv_sec
= (0 >= timeout
|| INT_MAX
<= timeout
) ? INT_MAX
: (int)(float)floor(timeout
);
1792 tv
->tv_usec
= (int)((timeout
- floor(timeout
)) * 1.0E6
);
1797 /* note that this returns a pointer to the min value, which won't have changed during
1798 the dictionary apply, since we've got the active sockets lock held */
1799 static void _calcMinTimeout_locked(const void* val
, void* ctxt
)
1801 CFSocketRef s
= (CFSocketRef
) val
;
1802 struct timeval
** minTime
= (struct timeval
**) ctxt
;
1803 if (timerisset(&s
->_readBufferTimeout
) && (*minTime
== NULL
|| timercmp(&s
->_readBufferTimeout
, *minTime
, <)))
1804 *minTime
= &s
->_readBufferTimeout
;
1805 else if (s
->_leftoverBytes
) {
1806 /* If there's anyone with leftover bytes, they'll need to be awoken immediately */
1807 static struct timeval sKickerTime
= { 0, 0 };
1808 *minTime
= &sKickerTime
;
1812 void __CFSocketSetSocketReadBufferAttrs(CFSocketRef s
, CFTimeInterval timeout
, CFIndex length
)
1814 struct timeval timeoutVal
;
1816 intervalToTimeval(timeout
, &timeoutVal
);
1818 /* lock ordering is socket lock, activesocketslock */
1819 /* activesocketslock protects our timeout calculation */
1821 __CFLock(&__CFActiveSocketsLock
);
1823 if (s
->_bytesToBuffer
!= length
) {
1824 CFIndex ctBuffer
= s
->_bytesToBufferPos
- s
->_bytesToBufferReadPos
;
1827 /* As originally envisaged, you were supposed to be sure to drain the buffer before
1828 * issuing another request on the socket. In practice, there seem to be times when we want to re-use
1829 * the stream (or perhaps, are on our way to closing it out) and this policy doesn't work so well.
1830 * So, if someone changes the buffer size while we have bytes already buffered, we put them
1831 * aside and use them to satisfy any subsequent reads.
1833 #if defined(LOG_CFSOCKET)
1834 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);
1837 if (s
->_leftoverBytes
== NULL
)
1838 s
->_leftoverBytes
= CFDataCreateMutable(CFGetAllocator(s
), 0);
1840 /* append the current buffered bytes over. We'll keep draining _leftoverBytes while we have them... */
1841 CFDataAppendBytes(s
->_leftoverBytes
, CFDataGetBytePtr(s
->_readBuffer
) + s
->_bytesToBufferReadPos
, ctBuffer
);
1842 CFRelease(s
->_readBuffer
);
1843 s
->_readBuffer
= NULL
;
1845 s
->_bytesToBuffer
= 0;
1846 s
->_bytesToBufferPos
= 0;
1847 s
->_bytesToBufferReadPos
= 0;
1850 s
->_bytesToBuffer
= 0;
1851 s
->_bytesToBufferPos
= 0;
1852 s
->_bytesToBufferReadPos
= 0;
1853 if (s
->_readBuffer
) {
1854 CFRelease(s
->_readBuffer
);
1855 s
->_readBuffer
= NULL
;
1857 // Zero length buffer, smash the timeout
1858 timeoutVal
.tv_sec
= 0;
1859 timeoutVal
.tv_usec
= 0;
1861 /* if the buffer shrank, we can re-use the old one */
1862 if (length
> s
->_bytesToBuffer
) {
1863 if (s
->_readBuffer
) {
1864 CFRelease(s
->_readBuffer
);
1865 s
->_readBuffer
= NULL
;
1869 s
->_bytesToBuffer
= length
;
1870 s
->_bytesToBufferPos
= 0;
1871 s
->_bytesToBufferReadPos
= 0;
1872 if (s
->_readBuffer
== NULL
) {
1873 s
->_readBuffer
= CFDataCreateMutable(kCFAllocatorSystemDefault
, length
);
1874 CFDataSetLength(s
->_readBuffer
, length
);
1879 if (timercmp(&s
->_readBufferTimeout
, &timeoutVal
, !=)) {
1880 s
->_readBufferTimeout
= timeoutVal
;
1881 __CFReadSocketsTimeoutInvalid
= true;
1884 __CFUnlock(&__CFActiveSocketsLock
);
1885 __CFSocketUnlock(s
);
1888 CFIndex
__CFSocketRead(CFSocketRef s
, UInt8
* buffer
, CFIndex length
, int* error
)
1890 #if defined(LOG_CFSOCKET)
1891 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
);
1894 CFIndex result
= -1;
1900 /* Any leftover buffered bytes? */
1901 if (s
->_leftoverBytes
) {
1902 CFIndex ctBuffer
= CFDataGetLength(s
->_leftoverBytes
);
1904 fprintf(stderr
, "%s(%ld): WARNING: Draining %ld leftover bytes first\n\n", __FUNCTION__
, (long)__LINE__
, (long)ctBuffer
);
1906 if (ctBuffer
> length
)
1908 memcpy(buffer
, CFDataGetBytePtr(s
->_leftoverBytes
), ctBuffer
);
1909 if (ctBuffer
< CFDataGetLength(s
->_leftoverBytes
))
1910 CFDataReplaceBytes(s
->_leftoverBytes
, CFRangeMake(0, ctBuffer
), NULL
, 0);
1912 CFRelease(s
->_leftoverBytes
);
1913 s
->_leftoverBytes
= NULL
;
1919 /* return whatever we've buffered */
1920 if (s
->_bytesToBuffer
!= 0) {
1921 CFIndex ctBuffer
= s
->_bytesToBufferPos
- s
->_bytesToBufferReadPos
;
1923 /* drain our buffer first */
1924 if (ctBuffer
> length
)
1926 memcpy(buffer
, CFDataGetBytePtr(s
->_readBuffer
) + s
->_bytesToBufferReadPos
, ctBuffer
);
1927 s
->_bytesToBufferReadPos
+= ctBuffer
;
1928 if (s
->_bytesToBufferReadPos
== s
->_bytesToBufferPos
) {
1929 #if defined(LOG_CFSOCKET)
1930 fprintf(stdout
, "DRAINED BUFFER - SHOULD START BUFFERING AGAIN!\n");
1932 s
->_bytesToBufferPos
= 0;
1933 s
->_bytesToBufferReadPos
= 0;
1936 #if defined(LOG_CFSOCKET)
1937 fprintf(stdout
, "SLURPED %ld BYTES FROM BUFFER %ld LEFT TO READ!\n", ctBuffer
, length
);
1944 /* nothing buffered, or no buffer selected */
1946 /* Did we get an error on a previous read (or buffered read)? */
1947 if (s
->_bufferedReadError
!= 0) {
1948 #if defined(LOG_CFSOCKET)
1949 fprintf(stdout
, "RETURNING ERROR %d\n", s
->_bufferedReadError
);
1951 *error
= s
->_bufferedReadError
;
1956 /* nothing buffered, if we've hit eof, don't bother reading any more */
1958 #if defined(LOG_CFSOCKET)
1959 fprintf(stdout
, "RETURNING EOF\n");
1966 result
= read(CFSocketGetNative(s
), buffer
, length
);
1967 #if defined(LOG_CFSOCKET)
1968 fprintf(stdout
, "READ %ld bytes", result
);
1972 /* note that we hit EOF */
1974 } else if (result
< 0) {
1977 /* if it wasn't EAGAIN, record it (although we shouldn't get called again) */
1978 if (*error
!= EAGAIN
) {
1979 s
->_bufferedReadError
= *error
;
1984 __CFSocketUnlock(s
);
1989 Boolean
__CFSocketGetBytesAvailable(CFSocketRef s
, CFIndex
* ctBytesAvailable
)
1991 CFIndex ctBuffer
= s
->_bytesToBufferPos
- s
->_bytesToBufferReadPos
;
1992 if (ctBuffer
!= 0) {
1993 *ctBytesAvailable
= ctBuffer
;
1997 unsigned long bytesAvailable
;
1998 result
= ioctlsocket(CFSocketGetNative(s
), FIONREAD
, &bytesAvailable
);
2001 *ctBytesAvailable
= (CFIndex
) bytesAvailable
;
2006 #if defined(LOG_CFSOCKET)
2007 static void __CFSocketWriteSocketList(CFArrayRef sockets
, CFDataRef fdSet
, Boolean onlyIfSet
) {
2008 fd_set
*tempfds
= (fd_set
*)CFDataGetBytePtr(fdSet
);
2010 for (idx
= 0, cnt
= CFArrayGetCount(sockets
); idx
< cnt
; idx
++) {
2011 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(sockets
, idx
);
2012 if (FD_ISSET(s
->_socket
, tempfds
)) {
2013 fprintf(stdout
, "%d ", s
->_socket
);
2014 } else if (!onlyIfSet
) {
2015 fprintf(stdout
, "(%d) ", s
->_socket
);
2022 clearInvalidFileDescriptors(CFMutableDataRef d
)
2025 SInt32 count
= __CFSocketFdGetSize(d
);
2026 fd_set
* s
= (fd_set
*) CFDataGetMutableBytePtr(d
);
2027 for (SInt32 idx
= 0; idx
< count
; idx
++) {
2028 if (FD_ISSET(idx
, s
))
2029 if (! __CFNativeSocketIsValid(idx
)) {
2039 SInt32 selectError
= __CFSocketLastError();
2040 #if defined(LOG_CFSOCKET)
2041 fprintf(stdout
, "socket manager received error %ld from select\n", (long)selectError
);
2043 if (EBADF
== selectError
) {
2044 CFMutableArrayRef invalidSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
2046 __CFLock(&__CFActiveSocketsLock
);
2047 CFIndex cnt
= CFArrayGetCount(__CFWriteSockets
);
2049 for (idx
= 0; idx
< cnt
; idx
++) {
2050 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFWriteSockets
, idx
);
2051 if (!__CFNativeSocketIsValid(s
->_socket
)) {
2052 #if defined(LOG_CFSOCKET)
2053 fprintf(stdout
, "socket manager found write socket %d invalid\n", s
->_socket
);
2055 CFArrayAppendValue(invalidSockets
, s
);
2058 cnt
= CFArrayGetCount(__CFReadSockets
);
2059 for (idx
= 0; idx
< cnt
; idx
++) {
2060 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFReadSockets
, idx
);
2061 if (!__CFNativeSocketIsValid(s
->_socket
)) {
2062 #if defined(LOG_CFSOCKET)
2063 fprintf(stdout
, "socket manager found read socket %d invalid\n", s
->_socket
);
2065 CFArrayAppendValue(invalidSockets
, s
);
2070 cnt
= CFArrayGetCount(invalidSockets
);
2072 /* Note that we're doing this only when we got EBADF but otherwise
2073 * don't have an explicit bad descriptor. Note that the lock is held now.
2074 * Finally, note that cnt == 0 doesn't necessarily mean
2075 * that this loop will do anything, since fd's may have been invalidated
2076 * while we were in select.
2079 #if defined(LOG_CFSOCKET)
2080 fprintf(stdout
, "socket manager received EBADF(1): No sockets were marked as invalid, cleaning out fdsets\n");
2083 clearInvalidFileDescriptors(__CFReadSocketsFds
);
2084 clearInvalidFileDescriptors(__CFWriteSocketsFds
);
2087 __CFUnlock(&__CFActiveSocketsLock
);
2089 for (idx
= 0; idx
< cnt
; idx
++) {
2090 CFSocketInvalidate(((CFSocketRef
)CFArrayGetValueAtIndex(invalidSockets
, idx
)));
2092 CFRelease(invalidSockets
);
2096 static void *__CFSocketManager(void * arg
)
2098 pthread_setname_np("com.apple.CFSocket.private");
2099 if (objc_collectingEnabled()) objc_registerThreadWithCollector();
2100 SInt32 nrfds
, maxnrfds
, fdentries
= 1;
2102 fd_set
*exceptfds
= NULL
;
2103 fd_set
*writefds
= (fd_set
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, fdentries
* sizeof(fd_mask
), 0);
2104 fd_set
*readfds
= (fd_set
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, fdentries
* sizeof(fd_mask
), 0);
2107 uint8_t buffer
[256];
2108 CFMutableArrayRef selectedWriteSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
2109 CFMutableArrayRef selectedReadSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
2110 CFIndex selectedWriteSocketsIndex
= 0, selectedReadSocketsIndex
= 0;
2113 struct timeval
* pTimeout
= NULL
;
2114 struct timeval timeBeforeSelect
;
2117 __CFLock(&__CFActiveSocketsLock
);
2118 __CFSocketManagerIteration
++;
2119 #if defined(LOG_CFSOCKET)
2120 fprintf(stdout
, "socket manager iteration %lu looking at read sockets ", (unsigned long)__CFSocketManagerIteration
);
2121 __CFSocketWriteSocketList(__CFReadSockets
, __CFReadSocketsFds
, FALSE
);
2122 if (0 < CFArrayGetCount(__CFWriteSockets
)) {
2123 fprintf(stdout
, " and write sockets ");
2124 __CFSocketWriteSocketList(__CFWriteSockets
, __CFWriteSocketsFds
, FALSE
);
2126 fprintf(stdout
, "\n");
2128 rfds
= __CFSocketFdGetSize(__CFReadSocketsFds
);
2129 wfds
= __CFSocketFdGetSize(__CFWriteSocketsFds
);
2130 maxnrfds
= __CFMax(rfds
, wfds
);
2131 if (maxnrfds
> fdentries
* (int)NFDBITS
) {
2132 fdentries
= (maxnrfds
+ NFDBITS
- 1) / NFDBITS
;
2133 writefds
= (fd_set
*)CFAllocatorReallocate(kCFAllocatorSystemDefault
, writefds
, fdentries
* sizeof(fd_mask
), 0);
2134 readfds
= (fd_set
*)CFAllocatorReallocate(kCFAllocatorSystemDefault
, readfds
, fdentries
* sizeof(fd_mask
), 0);
2136 memset(writefds
, 0, fdentries
* sizeof(fd_mask
));
2137 memset(readfds
, 0, fdentries
* sizeof(fd_mask
));
2138 CFDataGetBytes(__CFWriteSocketsFds
, CFRangeMake(0, CFDataGetLength(__CFWriteSocketsFds
)), (UInt8
*)writefds
);
2139 CFDataGetBytes(__CFReadSocketsFds
, CFRangeMake(0, CFDataGetLength(__CFReadSocketsFds
)), (UInt8
*)readfds
);
2141 if (__CFReadSocketsTimeoutInvalid
) {
2142 struct timeval
* minTimeout
= NULL
;
2143 __CFReadSocketsTimeoutInvalid
= false;
2144 #if defined(LOG_CFSOCKET)
2145 fprintf(stdout
, "Figuring out which sockets have timeouts...\n");
2147 CFArrayApplyFunction(__CFReadSockets
, CFRangeMake(0, CFArrayGetCount(__CFReadSockets
)), _calcMinTimeout_locked
, (void*) &minTimeout
);
2149 if (minTimeout
== NULL
) {
2150 #if defined(LOG_CFSOCKET)
2151 fprintf(stdout
, "No one wants a timeout!\n");
2155 #if defined(LOG_CFSOCKET)
2156 fprintf(stdout
, "timeout will be %ld, %d!\n", minTimeout
->tv_sec
, minTimeout
->tv_usec
);
2164 #if defined(LOG_CFSOCKET)
2165 fprintf(stdout
, "select will have a %ld, %d timeout\n", pTimeout
->tv_sec
, pTimeout
->tv_usec
);
2167 gettimeofday(&timeBeforeSelect
, NULL
);
2170 __CFUnlock(&__CFActiveSocketsLock
);
2172 #if DEPLOYMENT_TARGET_WINDOWS
2173 // On Windows, select checks connection failed sockets via the exceptfds parameter. connection succeeded is checked via writefds. We need both.
2174 exceptfds
= writefds
;
2176 nrfds
= select(maxnrfds
, readfds
, writefds
, exceptfds
, pTimeout
);
2178 #if defined(LOG_CFSOCKET)
2179 fprintf(stdout
, "socket manager woke from select, ret=%ld\n", (long)nrfds
);
2183 * select returned a timeout
2186 struct timeval timeAfterSelect
;
2187 struct timeval deltaTime
;
2188 gettimeofday(&timeAfterSelect
, NULL
);
2189 /* timeBeforeSelect becomes the delta */
2190 timersub(&timeAfterSelect
, &timeBeforeSelect
, &deltaTime
);
2192 #if defined(LOG_CFSOCKET)
2193 fprintf(stdout
, "Socket manager received timeout - kicking off expired reads (expired delta %ld, %d)\n", deltaTime
.tv_sec
, deltaTime
.tv_usec
);
2196 __CFLock(&__CFActiveSocketsLock
);
2199 cnt
= CFArrayGetCount(__CFReadSockets
);
2200 for (idx
= 0; idx
< cnt
; idx
++) {
2201 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFReadSockets
, idx
);
2202 if (timerisset(&s
->_readBufferTimeout
) || s
->_leftoverBytes
) {
2203 CFSocketNativeHandle sock
= s
->_socket
;
2204 // We might have an new element in __CFReadSockets that we weren't listening to,
2205 // in which case we must be sure not to test a bit in the fdset that is
2206 // outside our mask size.
2207 Boolean sockInBounds
= (0 <= sock
&& sock
< maxnrfds
);
2208 /* if this sockets timeout is less than or equal elapsed time, then signal it */
2209 if (INVALID_SOCKET
!= sock
&& sockInBounds
) {
2210 #if defined(LOG_CFSOCKET)
2211 fprintf(stdout
, "Expiring socket %d (delta %ld, %d)\n", sock
, s
->_readBufferTimeout
.tv_sec
, s
->_readBufferTimeout
.tv_usec
);
2213 CFArraySetValueAtIndex(selectedReadSockets
, selectedReadSocketsIndex
, s
);
2214 selectedReadSocketsIndex
++;
2215 /* socket is removed from fds here, will be restored in read handling or in perform function */
2216 if (!tempfds
) tempfds
= (fd_set
*)CFDataGetMutableBytePtr(__CFReadSocketsFds
);
2217 FD_CLR(sock
, tempfds
);
2222 __CFUnlock(&__CFActiveSocketsLock
);
2224 /* and below, we dispatch through the normal read dispatch mechanism */
2228 manageSelectError();
2231 if (FD_ISSET(__CFWakeupSocketPair
[1], readfds
)) {
2232 recv(__CFWakeupSocketPair
[1], (char *)buffer
, sizeof(buffer
), 0);
2233 #if defined(LOG_CFSOCKET)
2234 fprintf(stdout
, "socket manager received %c on wakeup socket\n", buffer
[0]);
2237 __CFLock(&__CFActiveSocketsLock
);
2239 cnt
= CFArrayGetCount(__CFWriteSockets
);
2240 for (idx
= 0; idx
< cnt
; idx
++) {
2241 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFWriteSockets
, idx
);
2242 CFSocketNativeHandle sock
= s
->_socket
;
2243 // We might have an new element in __CFWriteSockets that we weren't listening to,
2244 // in which case we must be sure not to test a bit in the fdset that is
2245 // outside our mask size.
2246 Boolean sockInBounds
= (0 <= sock
&& sock
< maxnrfds
);
2247 if (INVALID_SOCKET
!= sock
&& sockInBounds
) {
2248 if (FD_ISSET(sock
, writefds
)) {
2249 CFArraySetValueAtIndex(selectedWriteSockets
, selectedWriteSocketsIndex
, s
);
2250 selectedWriteSocketsIndex
++;
2251 /* socket is removed from fds here, restored by CFSocketReschedule */
2252 if (!tempfds
) tempfds
= (fd_set
*)CFDataGetMutableBytePtr(__CFWriteSocketsFds
);
2253 FD_CLR(sock
, tempfds
);
2254 // CFLog(5, CFSTR("Manager: cleared socket %p from write fds"), s);
2259 cnt
= CFArrayGetCount(__CFReadSockets
);
2261 struct timeval timeNow
= { 0 };
2263 gettimeofday(&timeNow
, NULL
);
2266 for (idx
= 0; idx
< cnt
; idx
++) {
2267 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFReadSockets
, idx
);
2268 CFSocketNativeHandle sock
= s
->_socket
;
2269 // We might have an new element in __CFReadSockets that we weren't listening to,
2270 // in which case we must be sure not to test a bit in the fdset that is
2271 // outside our mask size.
2272 Boolean sockInBounds
= (0 <= sock
&& sock
< maxnrfds
);
2274 // Check if we hit the timeout
2275 s
->_hitTheTimeout
= false;
2276 if (pTimeout
&& sockInBounds
&& 0 != nrfds
&& !FD_ISSET(sock
, readfds
) &&
2277 timerisset(&s
->_readBufferTimeoutNotificationTime
) &&
2278 timercmp(&timeNow
, &s
->_readBufferTimeoutNotificationTime
, >))
2280 s
->_hitTheTimeout
= true;
2283 if (INVALID_SOCKET
!= sock
&& sockInBounds
&& (FD_ISSET(sock
, readfds
) || s
->_hitTheTimeout
)) {
2284 CFArraySetValueAtIndex(selectedReadSockets
, selectedReadSocketsIndex
, s
);
2285 selectedReadSocketsIndex
++;
2286 /* socket is removed from fds here, will be restored in read handling or in perform function */
2287 if (!tempfds
) tempfds
= (fd_set
*)CFDataGetMutableBytePtr(__CFReadSocketsFds
);
2288 FD_CLR(sock
, tempfds
);
2291 __CFUnlock(&__CFActiveSocketsLock
);
2293 for (idx
= 0; idx
< selectedWriteSocketsIndex
; idx
++) {
2294 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(selectedWriteSockets
, idx
);
2295 if (kCFNull
== (CFNullRef
)s
) continue;
2296 #if defined(LOG_CFSOCKET)
2297 fprintf(stdout
, "socket manager signaling socket %d for write\n", s
->_socket
);
2299 __CFSocketHandleWrite(s
, FALSE
);
2300 CFArraySetValueAtIndex(selectedWriteSockets
, idx
, kCFNull
);
2302 selectedWriteSocketsIndex
= 0;
2304 for (idx
= 0; idx
< selectedReadSocketsIndex
; idx
++) {
2305 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(selectedReadSockets
, idx
);
2306 if (kCFNull
== (CFNullRef
)s
) continue;
2307 #if defined(LOG_CFSOCKET)
2308 fprintf(stdout
, "socket manager signaling socket %d for read\n", s
->_socket
);
2310 __CFSocketHandleRead(s
, nrfds
== 0 || s
->_hitTheTimeout
);
2311 CFArraySetValueAtIndex(selectedReadSockets
, idx
, kCFNull
);
2313 selectedReadSocketsIndex
= 0;
2318 static CFStringRef
__CFSocketCopyDescription(CFTypeRef cf
) {
2319 CFSocketRef s
= (CFSocketRef
)cf
;
2320 CFMutableStringRef result
;
2321 CFStringRef contextDesc
= NULL
;
2322 void *contextInfo
= NULL
;
2323 CFStringRef (*contextCopyDescription
)(const void *info
) = NULL
;
2324 result
= CFStringCreateMutable(CFGetAllocator(s
), 0);
2326 void *addr
= s
->_callout
;
2327 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2329 const char *name
= (dladdr(addr
, &info
) && info
.dli_saddr
== addr
&& info
.dli_sname
) ? info
.dli_sname
: "???";
2331 // don't bother trying to figure out callout names
2332 const char *name
= "<unknown>";
2334 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
);
2335 contextInfo
= s
->_context
.info
;
2336 contextCopyDescription
= s
->_context
.copyDescription
;
2337 __CFSocketUnlock(s
);
2338 if (NULL
!= contextInfo
&& NULL
!= contextCopyDescription
) {
2339 contextDesc
= (CFStringRef
)contextCopyDescription(contextInfo
);
2341 if (NULL
== contextDesc
) {
2342 contextDesc
= CFStringCreateWithFormat(CFGetAllocator(s
), NULL
, CFSTR("<CFSocket context %p>"), contextInfo
);
2344 CFStringAppend(result
, contextDesc
);
2345 CFStringAppend(result
, CFSTR("}"));
2346 CFRelease(contextDesc
);
2350 static void __CFSocketDeallocate(CFTypeRef cf
) {
2351 /* Since CFSockets are cached, we can only get here sometime after being invalidated */
2352 CFSocketRef s
= (CFSocketRef
)cf
;
2353 if (NULL
!= s
->_address
) {
2354 CFRelease(s
->_address
);
2357 if (NULL
!= s
->_readBuffer
) {
2358 CFRelease(s
->_readBuffer
);
2359 s
->_readBuffer
= NULL
;
2361 if (NULL
!= s
->_leftoverBytes
) {
2362 CFRelease(s
->_leftoverBytes
);
2363 s
->_leftoverBytes
= NULL
;
2365 timerclear(&s
->_readBufferTimeout
);
2366 s
->_bytesToBuffer
= 0;
2367 s
->_bytesToBufferPos
= 0;
2368 s
->_bytesToBufferReadPos
= 0;
2370 s
->_bufferedReadError
= 0;
2373 static CFTypeID __kCFSocketTypeID
= _kCFRuntimeNotATypeID
;
2375 static const CFRuntimeClass __CFSocketClass
= {
2380 __CFSocketDeallocate
,
2384 __CFSocketCopyDescription
2387 CFTypeID
CFSocketGetTypeID(void) {
2388 static dispatch_once_t initOnce
;
2389 dispatch_once(&initOnce
, ^{
2390 __kCFSocketTypeID
= _CFRuntimeRegisterClass(&__CFSocketClass
); // initOnce covered
2391 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2393 int ret1
= getrlimit(RLIMIT_NOFILE
, &lim1
);
2394 int mib
[] = {CTL_KERN
, KERN_MAXFILESPERPROC
};
2396 size_t len
= sizeof(int);
2397 int ret0
= sysctl(mib
, 2, &maxfd
, &len
, NULL
, 0);
2398 if (0 == ret0
&& 0 == ret1
&& lim1
.rlim_max
< maxfd
) maxfd
= lim1
.rlim_max
;
2399 if (0 == ret1
&& lim1
.rlim_cur
< maxfd
) {
2400 struct rlimit lim2
= lim1
;
2401 lim2
.rlim_cur
+= 2304;
2402 if (maxfd
< lim2
.rlim_cur
) lim2
.rlim_cur
= maxfd
;
2403 setrlimit(RLIMIT_NOFILE
, &lim2
);
2404 // we try, but do not go to extraordinary measures
2408 return __kCFSocketTypeID
;
2411 #if DEPLOYMENT_TARGET_WINDOWS
2417 static unsigned __stdcall
__CFWinThreadFunc(void *arg
) {
2418 struct _args
*args
= (struct _args
*)arg
;
2419 ((void (*)(void *))args
->func
)(args
->arg
);
2420 CloseHandle(args
->handle
);
2421 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, arg
);
2427 static CFSocketRef
_CFSocketCreateWithNative(CFAllocatorRef allocator
, CFSocketNativeHandle sock
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
, Boolean useExistingInstance
) {
2430 int typeSize
= sizeof(memory
->_socketType
);
2431 __CFLock(&__CFActiveSocketsLock
);
2432 if (NULL
== __CFReadSockets
) __CFSocketInitializeSockets();
2433 __CFUnlock(&__CFActiveSocketsLock
);
2434 __CFLock(&__CFAllSocketsLock
);
2435 if (NULL
== __CFAllSockets
) {
2436 __CFAllSockets
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, &kCFTypeDictionaryValueCallBacks
);
2438 if (INVALID_SOCKET
!= sock
&& CFDictionaryGetValueIfPresent(__CFAllSockets
, (void *)(uintptr_t)sock
, (const void **)&memory
)) {
2439 if (useExistingInstance
) {
2440 __CFUnlock(&__CFAllSocketsLock
);
2444 #if defined(LOG_CFSOCKET)
2445 fprintf(stdout
, "useExistingInstance is FALSE, removing existing instance %p from __CFAllSockets\n", memory
);
2447 __CFUnlock(&__CFAllSocketsLock
);
2448 CFSocketInvalidate(memory
);
2449 __CFLock(&__CFAllSocketsLock
);
2452 memory
= (CFSocketRef
)_CFRuntimeCreateInstance(allocator
, CFSocketGetTypeID(), sizeof(struct __CFSocket
) - sizeof(CFRuntimeBase
), NULL
);
2453 if (NULL
== memory
) {
2454 __CFUnlock(&__CFAllSocketsLock
);
2457 __CFSocketSetCallBackTypes(memory
, callBackTypes
);
2458 if (INVALID_SOCKET
!= sock
) __CFSocketSetValid(memory
);
2459 __CFSocketUnsetWriteSignalled(memory
);
2460 __CFSocketUnsetReadSignalled(memory
);
2461 memory
->_f
.client
= ((callBackTypes
& (~kCFSocketConnectCallBack
)) & (~kCFSocketWriteCallBack
)) | kCFSocketCloseOnInvalidate
;
2462 memory
->_f
.disabled
= 0;
2463 memory
->_f
.connected
= FALSE
;
2464 memory
->_f
.writableHint
= FALSE
;
2465 memory
->_f
.closeSignaled
= FALSE
;
2466 memory
->_lock
= CFLockInit
;
2467 memory
->_writeLock
= CFLockInit
;
2468 memory
->_socket
= sock
;
2469 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
2470 memory
->_errorCode
= 0;
2471 memory
->_address
= NULL
;
2472 memory
->_peerAddress
= NULL
;
2473 memory
->_socketSetCount
= 0;
2474 memory
->_source0
= NULL
;
2475 if (INVALID_SOCKET
!= sock
) {
2476 memory
->_runLoops
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
);
2478 memory
->_runLoops
= NULL
;
2480 memory
->_callout
= callout
;
2481 memory
->_dataQueue
= NULL
;
2482 memory
->_addressQueue
= NULL
;
2483 memory
->_context
.info
= 0;
2484 memory
->_context
.retain
= 0;
2485 memory
->_context
.release
= 0;
2486 memory
->_context
.copyDescription
= 0;
2487 timerclear(&memory
->_readBufferTimeout
);
2488 timerclear(&memory
->_readBufferTimeoutNotificationTime
);
2489 memory
->_hitTheTimeout
= false;
2490 memory
->_readBuffer
= NULL
;
2491 memory
->_bytesToBuffer
= 0;
2492 memory
->_bytesToBufferPos
= 0;
2493 memory
->_bytesToBufferReadPos
= 0;
2494 memory
->_atEOF
= false;
2495 memory
->_bufferedReadError
= 0;
2496 memory
->_leftoverBytes
= NULL
;
2498 if (INVALID_SOCKET
!= sock
) CFDictionaryAddValue(__CFAllSockets
, (void *)(uintptr_t)sock
, memory
);
2499 if (NULL
== __CFSocketManagerThread
) {
2500 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
2502 pthread_attr_t attr
;
2503 pthread_attr_init(&attr
);
2504 pthread_attr_setscope(&attr
, PTHREAD_SCOPE_SYSTEM
);
2505 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
2506 pthread_attr_set_qos_class_np(&attr
, qos_class_main(), 0);
2507 pthread_create(&tid
, &attr
, __CFSocketManager
, 0);
2508 pthread_attr_destroy(&attr
);
2509 //warning CF: we dont actually know that a pthread_t is the same size as void *
2510 __CFSocketManagerThread
= (void *)tid
;
2511 #elif DEPLOYMENT_TARGET_WINDOWS
2513 struct _args
*args
= (struct _args
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(struct _args
), 0);
2514 if (__CFOASafe
) __CFSetLastAllocationEventName(args
, "CFUtilities (thread-args)");
2516 args
->func
= __CFSocketManager
;
2518 /* The thread is created suspended, because otherwise there would be a race between the assignment below of the handle field, and it's possible use in the thread func above. */
2519 args
->handle
= (HANDLE
)_beginthreadex(NULL
, 0, __CFWinThreadFunc
, args
, CREATE_SUSPENDED
, &tid
);
2520 handle
= args
->handle
;
2521 ResumeThread(handle
);
2522 __CFSocketManagerThread
= handle
;
2525 __CFUnlock(&__CFAllSocketsLock
);
2526 if (NULL
!= context
) {
2527 void *contextInfo
= context
->retain
? (void *)context
->retain(context
->info
) : context
->info
;
2528 __CFSocketLock(memory
);
2529 memory
->_context
.retain
= context
->retain
;
2530 memory
->_context
.release
= context
->release
;
2531 memory
->_context
.copyDescription
= context
->copyDescription
;
2532 memory
->_context
.info
= contextInfo
;
2533 __CFSocketUnlock(memory
);
2535 #if defined(LOG_CFSOCKET)
2536 CFLog(5, CFSTR("CFSocketCreateWithNative(): created socket %p (%d) with callbacks 0x%x"), memory
, memory
->_socket
, callBackTypes
);
2541 CFSocketRef
CFSocketCreateWithNative(CFAllocatorRef allocator
, CFSocketNativeHandle sock
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
) {
2542 return _CFSocketCreateWithNative(allocator
, sock
, callBackTypes
, callout
, context
, TRUE
);
2545 void CFSocketInvalidate(CFSocketRef s
) {
2546 // CFLog(5, CFSTR("CFSocketInvalidate(%p) starting"), s);
2548 UInt32 previousSocketManagerIteration
;
2549 __CFGenericValidateType(s
, CFSocketGetTypeID());
2550 #if defined(LOG_CFSOCKET)
2551 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
);
2554 __CFLock(&__CFAllSocketsLock
);
2556 if (__CFSocketIsValid(s
)) {
2558 CFRunLoopSourceRef source0
;
2559 void *contextInfo
= NULL
;
2560 void (*contextRelease
)(const void *info
) = NULL
;
2561 __CFSocketUnsetValid(s
);
2562 __CFSocketUnsetWriteSignalled(s
);
2563 __CFSocketUnsetReadSignalled(s
);
2564 __CFLock(&__CFActiveSocketsLock
);
2565 idx
= CFArrayGetFirstIndexOfValue(__CFWriteSockets
, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets
)), s
);
2567 CFArrayRemoveValueAtIndex(__CFWriteSockets
, idx
);
2568 __CFSocketClearFDForWrite(s
);
2570 // No need to clear FD's for V1 sources, since we'll just throw the whole event away
2571 idx
= CFArrayGetFirstIndexOfValue(__CFReadSockets
, CFRangeMake(0, CFArrayGetCount(__CFReadSockets
)), s
);
2573 CFArrayRemoveValueAtIndex(__CFReadSockets
, idx
);
2574 __CFSocketClearFDForRead(s
);
2576 previousSocketManagerIteration
= __CFSocketManagerIteration
;
2577 __CFUnlock(&__CFActiveSocketsLock
);
2578 CFDictionaryRemoveValue(__CFAllSockets
, (void *)(uintptr_t)(s
->_socket
));
2579 if ((s
->_f
.client
& kCFSocketCloseOnInvalidate
) != 0) closesocket(s
->_socket
);
2580 s
->_socket
= INVALID_SOCKET
;
2581 if (NULL
!= s
->_peerAddress
) {
2582 CFRelease(s
->_peerAddress
);
2583 s
->_peerAddress
= NULL
;
2585 if (NULL
!= s
->_dataQueue
) {
2586 CFRelease(s
->_dataQueue
);
2587 s
->_dataQueue
= NULL
;
2589 if (NULL
!= s
->_addressQueue
) {
2590 CFRelease(s
->_addressQueue
);
2591 s
->_addressQueue
= NULL
;
2593 s
->_socketSetCount
= 0;
2595 // we'll need this later
2596 CFArrayRef runLoops
= (CFArrayRef
)CFRetain(s
->_runLoops
);
2597 CFRelease(s
->_runLoops
);
2599 s
->_runLoops
= NULL
;
2600 source0
= s
->_source0
;
2602 contextInfo
= s
->_context
.info
;
2603 contextRelease
= s
->_context
.release
;
2604 s
->_context
.info
= 0;
2605 s
->_context
.retain
= 0;
2606 s
->_context
.release
= 0;
2607 s
->_context
.copyDescription
= 0;
2608 __CFSocketUnlock(s
);
2610 // Do this after the socket unlock to avoid deadlock (10462525)
2611 for (idx
= CFArrayGetCount(runLoops
); idx
--;) {
2612 CFRunLoopWakeUp((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoops
, idx
));
2614 CFRelease(runLoops
);
2616 if (NULL
!= contextRelease
) {
2617 contextRelease(contextInfo
);
2619 if (NULL
!= source0
) {
2620 CFRunLoopSourceInvalidate(source0
);
2624 __CFSocketUnlock(s
);
2626 __CFUnlock(&__CFAllSocketsLock
);
2628 #if defined(LOG_CFSOCKET)
2629 CFLog(5, CFSTR("CFSocketInvalidate(%p) done"), s
);
2633 Boolean
CFSocketIsValid(CFSocketRef s
) {
2635 __CFGenericValidateType(s
, CFSocketGetTypeID());
2636 return __CFSocketIsValid(s
);
2639 CFSocketNativeHandle
CFSocketGetNative(CFSocketRef s
) {
2641 __CFGenericValidateType(s
, CFSocketGetTypeID());
2645 CFDataRef
CFSocketCopyAddress(CFSocketRef s
) {
2647 CFDataRef result
= NULL
;
2648 __CFGenericValidateType(s
, CFSocketGetTypeID());
2650 __CFSocketEstablishAddress(s
);
2651 if (NULL
!= s
->_address
) {
2652 result
= (CFDataRef
)CFRetain(s
->_address
);
2654 __CFSocketUnlock(s
);
2655 #if defined(LOG_CFSOCKET)
2656 CFLog(5, CFSTR("CFSocketCopyAddress(): created socket %p address %@"), s
, result
);
2661 CFDataRef
CFSocketCopyPeerAddress(CFSocketRef s
) {
2663 CFDataRef result
= NULL
;
2664 __CFGenericValidateType(s
, CFSocketGetTypeID());
2666 __CFSocketEstablishPeerAddress(s
);
2667 if (NULL
!= s
->_peerAddress
) {
2668 result
= (CFDataRef
)CFRetain(s
->_peerAddress
);
2670 __CFSocketUnlock(s
);
2671 #if defined(LOG_CFSOCKET)
2672 CFLog(5, CFSTR("CFSocketCopyAddress(): created socket %p peer address %@"), s
, result
);
2677 void CFSocketGetContext(CFSocketRef s
, CFSocketContext
*context
) {
2679 __CFGenericValidateType(s
, CFSocketGetTypeID());
2680 CFAssert1(0 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__
);
2681 *context
= s
->_context
;
2684 CFOptionFlags
CFSocketGetSocketFlags(CFSocketRef s
) {
2686 __CFGenericValidateType(s
, CFSocketGetTypeID());
2687 return s
->_f
.client
;
2690 void CFSocketSetSocketFlags(CFSocketRef s
, CFOptionFlags flags
) {
2692 __CFGenericValidateType(s
, CFSocketGetTypeID());
2694 #if defined(LOG_CFSOCKET)
2695 fprintf(stdout
, "setting flags for socket %d, from 0x%x to 0x%lx\n", s
->_socket
, s
->_f
.client
, flags
);
2697 s
->_f
.client
= flags
;
2698 __CFSocketUnlock(s
);
2699 // CFLog(5, CFSTR("CFSocketSetSocketFlags(%p, 0x%x)"), s, flags);
2702 void CFSocketDisableCallBacks(CFSocketRef s
, CFOptionFlags callBackTypes
) {
2704 Boolean wakeup
= false;
2705 uint8_t readCallBackType
;
2706 __CFGenericValidateType(s
, CFSocketGetTypeID());
2708 if (__CFSocketIsValid(s
) && __CFSocketIsScheduled(s
)) {
2709 callBackTypes
&= __CFSocketCallBackTypes(s
);
2710 readCallBackType
= __CFSocketReadCallBackType(s
);
2711 s
->_f
.disabled
|= callBackTypes
;
2712 #if defined(LOG_CFSOCKET)
2713 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
);
2715 __CFLock(&__CFActiveSocketsLock
);
2716 if ((readCallBackType
== kCFSocketAcceptCallBack
) || !__CFSocketIsConnectionOriented(s
)) s
->_f
.connected
= TRUE
;
2717 if (((callBackTypes
& kCFSocketWriteCallBack
) != 0) || (((callBackTypes
& kCFSocketConnectCallBack
) != 0) && !s
->_f
.connected
)) {
2718 if (__CFSocketClearFDForWrite(s
)) {
2719 // do not wake up the socket manager thread if all relevant write callbacks are disabled
2720 CFOptionFlags writeCallBacksAvailable
= __CFSocketCallBackTypes(s
) & (kCFSocketWriteCallBack
| kCFSocketConnectCallBack
);
2721 if (s
->_f
.connected
) writeCallBacksAvailable
&= ~kCFSocketConnectCallBack
;
2722 if ((s
->_f
.disabled
& writeCallBacksAvailable
) != writeCallBacksAvailable
) wakeup
= true;
2725 if (readCallBackType
!= kCFSocketNoCallBack
&& (callBackTypes
& readCallBackType
) != 0) {
2726 if (__CFSocketClearFDForRead(s
)) {
2727 // do not wake up the socket manager thread if callback type is read
2728 if (readCallBackType
!= kCFSocketReadCallBack
) wakeup
= true;
2731 __CFUnlock(&__CFActiveSocketsLock
);
2733 __CFSocketUnlock(s
);
2736 // "force" means to clear the disabled bits set by DisableCallBacks and always reenable.
2737 // if (!force) we respect those bits, meaning they may stop us from enabling.
2738 // In addition, if !force we assume that the sockets have already been added to the
2739 // __CFReadSockets and __CFWriteSockets arrays. This is true because the callbacks start
2740 // enabled when the CFSocket is created (at which time we enable with force).
2741 // Called with SocketLock held, returns with it released!
2742 void __CFSocketEnableCallBacks(CFSocketRef s
, CFOptionFlags callBackTypes
, Boolean force
, uint8_t wakeupChar
) {
2744 Boolean wakeup
= FALSE
;
2745 if (!callBackTypes
) {
2746 __CFSocketUnlock(s
);
2749 if (__CFSocketIsValid(s
) && __CFSocketIsScheduled(s
)) {
2750 Boolean turnOnWrite
= FALSE
, turnOnConnect
= FALSE
, turnOnRead
= FALSE
;
2751 uint8_t readCallBackType
= __CFSocketReadCallBackType(s
);
2752 callBackTypes
&= __CFSocketCallBackTypes(s
);
2753 if (force
) s
->_f
.disabled
&= ~callBackTypes
;
2754 #if defined(LOG_CFSOCKET)
2755 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
);
2757 /* We will wait for connection only for connection-oriented, non-rendezvous sockets that are not already connected. Mark others as already connected. */
2758 if ((readCallBackType
== kCFSocketAcceptCallBack
) || !__CFSocketIsConnectionOriented(s
)) s
->_f
.connected
= TRUE
;
2760 // First figure out what to turn on
2761 if (s
->_f
.connected
|| (callBackTypes
& kCFSocketConnectCallBack
) == 0) {
2762 // if we want write callbacks and they're not disabled...
2763 if ((callBackTypes
& kCFSocketWriteCallBack
) != 0 && (s
->_f
.disabled
& kCFSocketWriteCallBack
) == 0) turnOnWrite
= TRUE
;
2765 // if we want connect callbacks and they're not disabled...
2766 if ((callBackTypes
& kCFSocketConnectCallBack
) != 0 && (s
->_f
.disabled
& kCFSocketConnectCallBack
) == 0) turnOnConnect
= TRUE
;
2768 // if we want read callbacks and they're not disabled...
2769 if (readCallBackType
!= kCFSocketNoCallBack
&& (callBackTypes
& readCallBackType
) != 0 && (s
->_f
.disabled
& kCFSocketReadCallBack
) == 0) turnOnRead
= TRUE
;
2771 // Now turn on the callbacks we've determined that we want on
2772 if (turnOnRead
|| turnOnWrite
|| turnOnConnect
) {
2773 __CFLock(&__CFActiveSocketsLock
);
2774 if (turnOnWrite
|| turnOnConnect
) {
2776 SInt32 idx
= CFArrayGetFirstIndexOfValue(__CFWriteSockets
, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets
)), s
);
2777 if (kCFNotFound
== idx
) CFArrayAppendValue(__CFWriteSockets
, s
);
2778 // if (kCFNotFound == idx) CFLog(5, CFSTR("__CFSocketEnableCallBacks: put %p in __CFWriteSockets list due to force and non-presence"), s);
2780 if (__CFSocketSetFDForWrite(s
)) wakeup
= true;
2784 SInt32 idx
= CFArrayGetFirstIndexOfValue(__CFReadSockets
, CFRangeMake(0, CFArrayGetCount(__CFReadSockets
)), s
);
2785 if (kCFNotFound
== idx
) CFArrayAppendValue(__CFReadSockets
, s
);
2787 if (__CFSocketSetFDForRead(s
)) wakeup
= true;
2789 __CFUnlock(&__CFActiveSocketsLock
);
2792 __CFSocketUnlock(s
);
2795 void CFSocketEnableCallBacks(CFSocketRef s
, CFOptionFlags callBackTypes
) {
2797 __CFGenericValidateType(s
, CFSocketGetTypeID());
2799 __CFSocketEnableCallBacks(s
, callBackTypes
, TRUE
, 'r');
2800 // CFLog(5, CFSTR("CFSocketEnableCallBacks(%p, 0x%x) done"), s, callBackTypes);
2803 static void __CFSocketSchedule(void *info
, CFRunLoopRef rl
, CFStringRef mode
) {
2804 CFSocketRef s
= (CFSocketRef
)info
;
2806 //??? also need to arrange delivery of all pending data
2807 if (__CFSocketIsValid(s
)) {
2808 CFMutableArrayRef runLoopsOrig
= s
->_runLoops
;
2809 CFMutableArrayRef runLoopsCopy
= CFArrayCreateMutableCopy(kCFAllocatorSystemDefault
, 0, s
->_runLoops
);
2810 CFArrayAppendValue(runLoopsCopy
, rl
);
2811 s
->_runLoops
= runLoopsCopy
;
2812 CFRelease(runLoopsOrig
);
2813 s
->_socketSetCount
++;
2814 // Since the v0 source is listened to on the SocketMgr thread, no matter how many modes it
2815 // is added to we just need to enable it there once (and _socketSetCount gives us a refCount
2816 // to know when we can finally disable it).
2817 if (1 == s
->_socketSetCount
) {
2818 #if defined(LOG_CFSOCKET)
2819 fprintf(stdout
, "scheduling socket %d\n", s
->_socket
);
2821 // CFLog(5, CFSTR("__CFSocketSchedule(%p, %p, %p)"), s, rl, mode);
2822 __CFSocketEnableCallBacks(s
, __CFSocketCallBackTypes(s
), TRUE
, 's'); // unlocks s
2824 __CFSocketUnlock(s
);
2826 __CFSocketUnlock(s
);
2829 static void __CFSocketCancel(void *info
, CFRunLoopRef rl
, CFStringRef mode
) {
2830 CFSocketRef s
= (CFSocketRef
)info
;
2833 s
->_socketSetCount
--;
2834 if (0 == s
->_socketSetCount
) {
2835 __CFLock(&__CFActiveSocketsLock
);
2836 idx
= CFArrayGetFirstIndexOfValue(__CFWriteSockets
, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets
)), s
);
2838 // CFLog(5, CFSTR("__CFSocketCancel: removing %p from __CFWriteSockets list"), s);
2839 CFArrayRemoveValueAtIndex(__CFWriteSockets
, idx
);
2840 __CFSocketClearFDForWrite(s
);
2842 idx
= CFArrayGetFirstIndexOfValue(__CFReadSockets
, CFRangeMake(0, CFArrayGetCount(__CFReadSockets
)), s
);
2844 CFArrayRemoveValueAtIndex(__CFReadSockets
, idx
);
2845 __CFSocketClearFDForRead(s
);
2847 __CFUnlock(&__CFActiveSocketsLock
);
2849 if (NULL
!= s
->_runLoops
) {
2850 CFMutableArrayRef runLoopsOrig
= s
->_runLoops
;
2851 CFMutableArrayRef runLoopsCopy
= CFArrayCreateMutableCopy(kCFAllocatorSystemDefault
, 0, s
->_runLoops
);
2852 idx
= CFArrayGetFirstIndexOfValue(runLoopsCopy
, CFRangeMake(0, CFArrayGetCount(runLoopsCopy
)), rl
);
2853 if (0 <= idx
) CFArrayRemoveValueAtIndex(runLoopsCopy
, idx
);
2854 s
->_runLoops
= runLoopsCopy
;
2855 CFRelease(runLoopsOrig
);
2857 __CFSocketUnlock(s
);
2860 // Note: must be called with socket lock held, then returns with it released
2861 // Used by both the v0 and v1 RunLoopSource perform routines
2862 static void __CFSocketDoCallback(CFSocketRef s
, CFDataRef data
, CFDataRef address
, CFSocketNativeHandle sock
) {
2863 CFSocketCallBack callout
= NULL
;
2864 void *contextInfo
= NULL
;
2865 SInt32 errorCode
= 0;
2866 Boolean readSignalled
= false, writeSignalled
= false, connectSignalled
= false, calledOut
= false;
2867 uint8_t readCallBackType
, callBackTypes
;
2869 callBackTypes
= __CFSocketCallBackTypes(s
);
2870 readCallBackType
= __CFSocketReadCallBackType(s
);
2871 readSignalled
= __CFSocketIsReadSignalled(s
);
2872 writeSignalled
= __CFSocketIsWriteSignalled(s
);
2873 connectSignalled
= writeSignalled
&& !s
->_f
.connected
;
2874 __CFSocketUnsetReadSignalled(s
);
2875 __CFSocketUnsetWriteSignalled(s
);
2876 callout
= s
->_callout
;
2877 contextInfo
= s
->_context
.info
;
2878 #if defined(LOG_CFSOCKET)
2879 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
);
2881 if (writeSignalled
) {
2882 errorCode
= s
->_errorCode
;
2883 s
->_f
.connected
= TRUE
;
2885 __CFSocketUnlock(s
);
2886 if ((callBackTypes
& kCFSocketConnectCallBack
) != 0) {
2887 if (connectSignalled
&& (!calledOut
|| CFSocketIsValid(s
))) {
2888 // CFLog(5, CFSTR("__CFSocketPerformV0(%p) doing connect callback, error: %d"), s, errorCode);
2890 #if defined(LOG_CFSOCKET)
2891 fprintf(stdout
, "perform calling out error %ld to socket %d\n", (long)errorCode
, s
->_socket
);
2893 if (callout
) callout(s
, kCFSocketConnectCallBack
, NULL
, &errorCode
, contextInfo
);
2896 #if defined(LOG_CFSOCKET)
2897 fprintf(stdout
, "perform calling out connect to socket %d\n", s
->_socket
);
2899 if (callout
) callout(s
, kCFSocketConnectCallBack
, NULL
, NULL
, contextInfo
);
2904 if (kCFSocketDataCallBack
== readCallBackType
) {
2905 if (NULL
!= data
&& (!calledOut
|| CFSocketIsValid(s
))) {
2906 SInt32 datalen
= CFDataGetLength(data
);
2907 #if defined(LOG_CFSOCKET)
2908 fprintf(stdout
, "perform calling out data of length %ld to socket %d\n", (long)datalen
, s
->_socket
);
2910 if (callout
) callout(s
, kCFSocketDataCallBack
, address
, data
, contextInfo
);
2912 if (0 == datalen
) CFSocketInvalidate(s
);
2914 } else if (kCFSocketAcceptCallBack
== readCallBackType
) {
2915 if (INVALID_SOCKET
!= sock
&& (!calledOut
|| CFSocketIsValid(s
))) {
2916 #if defined(LOG_CFSOCKET)
2917 fprintf(stdout
, "perform calling out accept of socket %d to socket %d\n", sock
, s
->_socket
);
2919 if (callout
) callout(s
, kCFSocketAcceptCallBack
, address
, &sock
, contextInfo
);
2922 } else if (kCFSocketReadCallBack
== readCallBackType
) {
2923 if (readSignalled
&& (!calledOut
|| CFSocketIsValid(s
))) {
2924 #if defined(LOG_CFSOCKET)
2925 fprintf(stdout
, "perform calling out read to socket %d\n", s
->_socket
);
2927 // CFLog(5, CFSTR("__CFSocketPerformV0(%p) doing read callback"), s);
2928 if (callout
) callout(s
, kCFSocketReadCallBack
, NULL
, NULL
, contextInfo
);
2932 if ((callBackTypes
& kCFSocketWriteCallBack
) != 0) {
2933 if (writeSignalled
&& !errorCode
&& (!calledOut
|| CFSocketIsValid(s
))) {
2934 #if defined(LOG_CFSOCKET)
2935 fprintf(stdout
, "perform calling out write to socket %d\n", s
->_socket
);
2937 // CFLog(5, CFSTR("__CFSocketPerformV0(%p) doing write callback"), s);
2938 if (callout
) callout(s
, kCFSocketWriteCallBack
, NULL
, NULL
, contextInfo
);
2944 static void __CFSocketPerformV0(void *info
) {
2945 CFSocketRef s
= (CFSocketRef
)info
;
2946 CFDataRef data
= NULL
;
2947 CFDataRef address
= NULL
;
2948 CFSocketNativeHandle sock
= INVALID_SOCKET
;
2949 uint8_t readCallBackType
, callBackTypes
;
2950 CFRunLoopRef rl
= NULL
;
2951 // CFLog(5, CFSTR("__CFSocketPerformV0(%p) starting"), s);
2954 if (!__CFSocketIsValid(s
)) {
2955 __CFSocketUnlock(s
);
2958 callBackTypes
= __CFSocketCallBackTypes(s
);
2959 readCallBackType
= __CFSocketReadCallBackType(s
);
2960 CFOptionFlags callBacksSignalled
= 0;
2961 if (__CFSocketIsReadSignalled(s
)) callBacksSignalled
|= readCallBackType
;
2962 if (__CFSocketIsWriteSignalled(s
)) callBacksSignalled
|= kCFSocketWriteCallBack
;
2964 if (kCFSocketDataCallBack
== readCallBackType
) {
2965 if (NULL
!= s
->_dataQueue
&& 0 < CFArrayGetCount(s
->_dataQueue
)) {
2966 data
= (CFDataRef
)CFArrayGetValueAtIndex(s
->_dataQueue
, 0);
2968 CFArrayRemoveValueAtIndex(s
->_dataQueue
, 0);
2969 address
= (CFDataRef
)CFArrayGetValueAtIndex(s
->_addressQueue
, 0);
2971 CFArrayRemoveValueAtIndex(s
->_addressQueue
, 0);
2973 } else if (kCFSocketAcceptCallBack
== readCallBackType
) {
2974 if (NULL
!= s
->_dataQueue
&& 0 < CFArrayGetCount(s
->_dataQueue
)) {
2975 sock
= (CFSocketNativeHandle
)(uintptr_t)CFArrayGetValueAtIndex(s
->_dataQueue
, 0);
2976 CFArrayRemoveValueAtIndex(s
->_dataQueue
, 0);
2977 address
= (CFDataRef
)CFArrayGetValueAtIndex(s
->_addressQueue
, 0);
2979 CFArrayRemoveValueAtIndex(s
->_addressQueue
, 0);
2983 __CFSocketDoCallback(s
, data
, address
, sock
); // does __CFSocketUnlock(s)
2984 if (NULL
!= data
) CFRelease(data
);
2985 if (NULL
!= address
) CFRelease(address
);
2988 if (__CFSocketIsValid(s
) && kCFSocketNoCallBack
!= readCallBackType
) {
2989 // if there's still more data, we want to wake back up right away
2990 if ((kCFSocketDataCallBack
== readCallBackType
|| kCFSocketAcceptCallBack
== readCallBackType
) && NULL
!= s
->_dataQueue
&& 0 < CFArrayGetCount(s
->_dataQueue
)) {
2991 #if defined(LOG_CFSOCKET)
2992 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
);
2994 CFRunLoopSourceSignal(s
->_source0
);
2995 CFMutableArrayRef runLoopsOrig
= (CFMutableArrayRef
)CFRetain(s
->_runLoops
);
2996 CFMutableArrayRef runLoopsCopy
= CFArrayCreateMutableCopy(kCFAllocatorSystemDefault
, 0, s
->_runLoops
);
2997 CFRunLoopSourceRef source0
= s
->_source0
;
2998 if (NULL
!= source0
&& !CFRunLoopSourceIsValid(source0
)) {
3001 if (source0
) CFRetain(source0
);
3002 __CFSocketUnlock(s
);
3003 rl
= __CFSocketCopyRunLoopToWakeUp(source0
, runLoopsCopy
);
3004 if (source0
) CFRelease(source0
);
3006 if (runLoopsOrig
== s
->_runLoops
) {
3007 s
->_runLoops
= runLoopsCopy
;
3008 runLoopsCopy
= NULL
;
3009 CFRelease(runLoopsOrig
);
3011 CFRelease(runLoopsOrig
);
3012 if (runLoopsCopy
) CFRelease(runLoopsCopy
);
3015 // Only reenable callbacks that are auto-reenabled
3016 __CFSocketEnableCallBacks(s
, callBacksSignalled
& s
->_f
.client
, FALSE
, 'p'); // unlocks s
3019 CFRunLoopWakeUp(rl
);
3022 // CFLog(5, CFSTR("__CFSocketPerformV0(%p) done"), s);
3025 CFRunLoopSourceRef
CFSocketCreateRunLoopSource(CFAllocatorRef allocator
, CFSocketRef s
, CFIndex order
) {
3027 CFRunLoopSourceRef result
= NULL
;
3028 __CFGenericValidateType(s
, CFSocketGetTypeID());
3030 if (__CFSocketIsValid(s
)) {
3031 if (NULL
!= s
->_source0
&& !CFRunLoopSourceIsValid(s
->_source0
)) {
3032 CFRelease(s
->_source0
);
3035 if (NULL
== s
->_source0
) {
3036 CFRunLoopSourceContext context
;
3037 context
.version
= 0;
3039 context
.retain
= CFRetain
;
3040 context
.release
= CFRelease
;
3041 context
.copyDescription
= CFCopyDescription
;
3042 context
.equal
= CFEqual
;
3043 context
.hash
= CFHash
;
3044 context
.schedule
= __CFSocketSchedule
;
3045 context
.cancel
= __CFSocketCancel
;
3046 context
.perform
= __CFSocketPerformV0
;
3047 s
->_source0
= CFRunLoopSourceCreate(allocator
, order
, &context
);
3049 CFRetain(s
->_source0
); /* This retain is for the receiver */
3050 result
= s
->_source0
;
3052 __CFSocketUnlock(s
);
3056 #endif /* NEW_SOCKET */
3060 static uint16_t __CFSocketDefaultNameRegistryPortNumber
= 2454;
3062 CONST_STRING_DECL(kCFSocketCommandKey
, "Command")
3063 CONST_STRING_DECL(kCFSocketNameKey
, "Name")
3064 CONST_STRING_DECL(kCFSocketValueKey
, "Value")
3065 CONST_STRING_DECL(kCFSocketResultKey
, "Result")
3066 CONST_STRING_DECL(kCFSocketErrorKey
, "Error")
3067 CONST_STRING_DECL(kCFSocketRegisterCommand
, "Register")
3068 CONST_STRING_DECL(kCFSocketRetrieveCommand
, "Retrieve")
3069 CONST_STRING_DECL(__kCFSocketRegistryRequestRunLoopMode
, "CFSocketRegistryRequest")
3071 static CFLock_t __CFSocketWriteLock_
= CFLockInit
;
3072 //#warning can only send on one socket at a time now
3074 CF_INLINE
void __CFSocketWriteLock(CFSocketRef s
) {
3075 __CFLock(& __CFSocketWriteLock_
);
3078 CF_INLINE
void __CFSocketWriteUnlock(CFSocketRef s
) {
3079 __CFUnlock(& __CFSocketWriteLock_
);
3084 CF_INLINE CFIndex
__CFSocketFdGetSize(CFDataRef fdSet
) {
3085 return NBBY
* CFDataGetLength(fdSet
);
3088 CF_INLINE Boolean
__CFSocketFdSet(CFSocketNativeHandle sock
, CFMutableDataRef fdSet
) {
3089 /* returns true if a change occurred, false otherwise */
3090 Boolean retval
= false;
3091 if (INVALID_SOCKET
!= sock
&& 0 <= sock
) {
3092 CFIndex numFds
= NBBY
* CFDataGetLength(fdSet
);
3094 if (sock
>= numFds
) {
3095 CFIndex oldSize
= numFds
/ NFDBITS
, newSize
= (sock
+ NFDBITS
) / NFDBITS
, changeInBytes
= (newSize
- oldSize
) * sizeof(fd_mask
);
3096 CFDataIncreaseLength(fdSet
, changeInBytes
);
3097 fds_bits
= (fd_mask
*)CFDataGetMutableBytePtr(fdSet
);
3098 memset(fds_bits
+ oldSize
, 0, changeInBytes
);
3100 fds_bits
= (fd_mask
*)CFDataGetMutableBytePtr(fdSet
);
3102 if (!FD_ISSET(sock
, (fd_set
*)fds_bits
)) {
3104 FD_SET(sock
, (fd_set
*)fds_bits
);
3112 //??? need timeout, error handling, retries
3113 CFSocketError
CFSocketSendData(CFSocketRef s
, CFDataRef address
, CFDataRef data
, CFTimeInterval timeout
) {
3115 const uint8_t *dataptr
, *addrptr
= NULL
;
3116 SInt32 datalen
, addrlen
= 0, size
= 0;
3117 CFSocketNativeHandle sock
= INVALID_SOCKET
;
3119 __CFGenericValidateType(s
, CFSocketGetTypeID());
3121 addrptr
= CFDataGetBytePtr(address
);
3122 addrlen
= CFDataGetLength(address
);
3124 dataptr
= CFDataGetBytePtr(data
);
3125 datalen
= CFDataGetLength(data
);
3126 if (CFSocketIsValid(s
)) sock
= CFSocketGetNative(s
);
3127 if (INVALID_SOCKET
!= sock
) {
3129 __CFSocketWriteLock(s
);
3130 tv
.tv_sec
= (timeout
<= 0.0 || (CFTimeInterval
)INT_MAX
<= timeout
) ? INT_MAX
: (int)floor(timeout
);
3131 tv
.tv_usec
= (int)floor(1.0e+6 * (timeout
- floor(timeout
)));
3132 setsockopt(sock
, SOL_SOCKET
, SO_SNDTIMEO
, (char *)&tv
, sizeof(tv
)); // cast for WinSock bad API
3133 if (NULL
!= addrptr
&& 0 < addrlen
) {
3134 size
= sendto(sock
, (char *)dataptr
, datalen
, 0, (struct sockaddr
*)addrptr
, addrlen
);
3136 size
= send(sock
, (char *)dataptr
, datalen
, 0);
3138 #if defined(LOG_CFSOCKET)
3139 fprintf(stdout
, "wrote %ld bytes to socket %d\n", (long)size
, sock
);
3141 __CFSocketWriteUnlock(s
);
3144 return (size
> 0) ? kCFSocketSuccess
: kCFSocketError
;
3147 CFSocketError
CFSocketSetAddress(CFSocketRef s
, CFDataRef address
) {
3149 struct sockaddr
*name
;
3151 __CFGenericValidateType(s
, CFSocketGetTypeID());
3152 if (NULL
== address
) return kCFSocketError
;
3153 if (!CFSocketIsValid(s
)) return kCFSocketError
;
3155 name
= (struct sockaddr
*)CFDataGetBytePtr(address
);
3156 namelen
= (socklen_t
)CFDataGetLength(address
);
3157 if (!name
|| namelen
<= 0) return kCFSocketError
;
3159 CFSocketNativeHandle sock
= CFSocketGetNative(s
);
3160 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
3161 // 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.
3162 // Max size is a size byte, plus family byte, plus path of 255, plus a null byte.
3164 if (namelen
> 2 && name
->sa_family
== AF_UNIX
) {
3165 // 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)
3166 socklen_t realLength
= (sizeof(*((struct sockaddr_un
*)name
)) - sizeof(((struct sockaddr_un
*)name
)->sun_path
) + strnlen(((struct sockaddr_un
*)name
)->sun_path
, namelen
- 2));
3167 if (realLength
> 255) return kCFSocketError
;
3169 // 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.
3170 namelen
= (socklen_t
)(((struct sockaddr_un
*)name
)->sun_len
);
3172 if (realLength
!= namelen
) {
3173 // 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.
3174 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."));
3175 memcpy(newName
, name
, realLength
);
3176 namelen
= realLength
;
3177 ((struct sockaddr_un
*)newName
)->sun_len
= realLength
;
3178 name
= (struct sockaddr
*)newName
;
3182 int result
= bind(sock
, name
, namelen
);
3186 //??? should return errno
3187 return (CFIndex
)result
;
3190 CFSocketError
CFSocketConnectToAddress(CFSocketRef s
, CFDataRef address
, CFTimeInterval timeout
) {
3192 //??? need error handling, retries
3193 const uint8_t *name
;
3194 SInt32 namelen
, result
= -1, connect_err
= 0, select_err
= 0;
3195 UInt32 yes
= 1, no
= 0;
3196 Boolean wasBlocking
= true;
3198 __CFGenericValidateType(s
, CFSocketGetTypeID());
3199 if (!CFSocketIsValid(s
)) return kCFSocketError
;
3200 name
= CFDataGetBytePtr(address
);
3201 namelen
= CFDataGetLength(address
);
3202 if (!name
|| namelen
<= 0) return kCFSocketError
;
3203 CFSocketNativeHandle sock
= CFSocketGetNative(s
);
3205 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
3206 SInt32 flags
= fcntl(sock
, F_GETFL
, 0);
3207 if (flags
>= 0) wasBlocking
= ((flags
& O_NONBLOCK
) == 0);
3208 if (wasBlocking
&& (timeout
> 0.0 || timeout
< 0.0)) ioctlsocket(sock
, FIONBIO
, (u_long
*)&yes
);
3210 // You can set but not get this flag in WIN32, so assume it was in non-blocking mode.
3211 // The downside is that when we leave this routine we'll leave it non-blocking,
3212 // whether it started that way or not.
3214 if (timeout
> 0.0 || timeout
< 0.0) ioctlsocket(sock
, FIONBIO
, (u_long
*)&yes
);
3215 wasBlocking
= false;
3217 result
= connect(sock
, (struct sockaddr
*)name
, namelen
);
3219 connect_err
= __CFSocketLastError();
3220 #if DEPLOYMENT_TARGET_WINDOWS
3221 if (connect_err
== WSAEWOULDBLOCK
) connect_err
= EINPROGRESS
;
3224 #if defined(LOG_CFSOCKET)
3225 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
);
3227 if (EINPROGRESS
== connect_err
&& timeout
>= 0.0) {
3228 /* select on socket */
3230 int error_size
= sizeof(select_err
);
3232 CFMutableDataRef fds
= CFDataCreateMutable(kCFAllocatorSystemDefault
, 0);
3233 __CFSocketFdSet(sock
, fds
);
3234 tv
.tv_sec
= (timeout
<= 0.0 || (CFTimeInterval
)INT_MAX
<= timeout
) ? INT_MAX
: (int)floor(timeout
);
3235 tv
.tv_usec
= (int)floor(1.0e+6 * (timeout
- floor(timeout
)));
3236 nrfds
= select(__CFSocketFdGetSize(fds
), NULL
, (fd_set
*)CFDataGetMutableBytePtr(fds
), NULL
, &tv
);
3238 select_err
= __CFSocketLastError();
3240 } else if (nrfds
== 0) {
3243 if (0 != getsockopt(sock
, SOL_SOCKET
, SO_ERROR
, (char *)&select_err
, (socklen_t
*)&error_size
)) select_err
= 0;
3244 result
= (select_err
== 0) ? 0 : -1;
3247 #if defined(LOG_CFSOCKET)
3248 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
);
3251 if (wasBlocking
&& (timeout
> 0.0 || timeout
< 0.0)) ioctlsocket(sock
, FIONBIO
, (u_long
*)&no
);
3252 if (EINPROGRESS
== connect_err
&& timeout
< 0.0) {
3254 #if defined(LOG_CFSOCKET)
3255 fprintf(stdout
, "connection attempt continues in background on socket %d\n", sock
);
3259 //??? should return errno
3263 CFSocketRef
CFSocketCreate(CFAllocatorRef allocator
, SInt32 protocolFamily
, SInt32 socketType
, SInt32 protocol
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
) {
3265 CFSocketNativeHandle sock
= INVALID_SOCKET
;
3266 CFSocketRef s
= NULL
;
3267 if (0 >= protocolFamily
) protocolFamily
= PF_INET
;
3268 if (PF_INET
== protocolFamily
) {
3269 if (0 >= socketType
) socketType
= SOCK_STREAM
;
3270 if (0 >= protocol
&& SOCK_STREAM
== socketType
) protocol
= IPPROTO_TCP
;
3271 if (0 >= protocol
&& SOCK_DGRAM
== socketType
) protocol
= IPPROTO_UDP
;
3273 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
3274 if (PF_LOCAL
== protocolFamily
&& 0 >= socketType
) socketType
= SOCK_STREAM
;
3276 #if DEPLOYMENT_TARGET_WINDOWS
3277 // make sure we've called proper Win32 startup facilities before socket()
3278 __CFSocketInitializeWinSock();
3280 sock
= socket(protocolFamily
, socketType
, protocol
);
3281 if (INVALID_SOCKET
!= sock
) {
3282 s
= CFSocketCreateWithNative(allocator
, sock
, callBackTypes
, callout
, context
);
3287 CFSocketRef
CFSocketCreateWithSocketSignature(CFAllocatorRef allocator
, const CFSocketSignature
*signature
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
) {
3289 CFSocketRef s
= CFSocketCreate(allocator
, signature
->protocolFamily
, signature
->socketType
, signature
->protocol
, callBackTypes
, callout
, context
);
3290 if (NULL
!= s
&& (!CFSocketIsValid(s
) || kCFSocketSuccess
!= CFSocketSetAddress(s
, signature
->address
))) {
3291 CFSocketInvalidate(s
);
3298 CFSocketRef
CFSocketCreateConnectedToSocketSignature(CFAllocatorRef allocator
, const CFSocketSignature
*signature
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
, CFTimeInterval timeout
) {
3300 CFSocketRef s
= CFSocketCreate(allocator
, signature
->protocolFamily
, signature
->socketType
, signature
->protocol
, callBackTypes
, callout
, context
);
3301 if (NULL
!= s
&& (!CFSocketIsValid(s
) || kCFSocketSuccess
!= CFSocketConnectToAddress(s
, signature
->address
, timeout
))) {
3302 CFSocketInvalidate(s
);
3310 CFSocketError
*error
;
3311 CFPropertyListRef
*value
;
3313 } __CFSocketNameRegistryResponse
;
3315 static void __CFSocketHandleNameRegistryReply(CFSocketRef s
, CFSocketCallBackType type
, CFDataRef address
, const void *data
, void *info
) {
3316 CFDataRef replyData
= (CFDataRef
)data
;
3317 __CFSocketNameRegistryResponse
*response
= (__CFSocketNameRegistryResponse
*)info
;
3318 CFDictionaryRef replyDictionary
= NULL
;
3319 CFPropertyListRef value
;
3320 replyDictionary
= (CFDictionaryRef
)CFPropertyListCreateWithData(kCFAllocatorSystemDefault
, replyData
, kCFPropertyListImmutable
, NULL
, NULL
);
3321 if (NULL
!= response
->error
) *(response
->error
) = kCFSocketError
;
3322 if (NULL
!= replyDictionary
) {
3323 if (CFGetTypeID((CFTypeRef
)replyDictionary
) == CFDictionaryGetTypeID() && NULL
!= (value
= CFDictionaryGetValue(replyDictionary
, kCFSocketResultKey
))) {
3324 if (NULL
!= response
->error
) *(response
->error
) = kCFSocketSuccess
;
3325 if (NULL
!= response
->value
) *(response
->value
) = CFRetain(value
);
3326 if (NULL
!= response
->address
) *(response
->address
) = address
? CFDataCreateCopy(kCFAllocatorSystemDefault
, address
) : NULL
;
3328 CFRelease(replyDictionary
);
3330 CFSocketInvalidate(s
);
3333 static void __CFSocketSendNameRegistryRequest(CFSocketSignature
*signature
, CFDictionaryRef requestDictionary
, __CFSocketNameRegistryResponse
*response
, CFTimeInterval timeout
) {
3334 CFDataRef requestData
= NULL
;
3335 CFSocketContext context
= {0, response
, NULL
, NULL
, NULL
};
3336 CFSocketRef s
= NULL
;
3337 CFRunLoopSourceRef source
= NULL
;
3338 if (NULL
!= response
->error
) *(response
->error
) = kCFSocketError
;
3339 requestData
= CFPropertyListCreateData(kCFAllocatorSystemDefault
, requestDictionary
, kCFPropertyListXMLFormat_v1_0
, 0, NULL
);
3340 if (NULL
!= requestData
) {
3341 if (NULL
!= response
->error
) *(response
->error
) = kCFSocketTimeout
;
3342 s
= CFSocketCreateConnectedToSocketSignature(kCFAllocatorSystemDefault
, signature
, kCFSocketDataCallBack
, __CFSocketHandleNameRegistryReply
, &context
, timeout
);
3344 if (kCFSocketSuccess
== CFSocketSendData(s
, NULL
, requestData
, timeout
)) {
3345 source
= CFSocketCreateRunLoopSource(kCFAllocatorSystemDefault
, s
, 0);
3346 CFRunLoopAddSource(CFRunLoopGetCurrent(), source
, __kCFSocketRegistryRequestRunLoopMode
);
3347 CFRunLoopRunInMode(__kCFSocketRegistryRequestRunLoopMode
, timeout
, false);
3350 CFSocketInvalidate(s
);
3353 CFRelease(requestData
);
3357 static void __CFSocketValidateSignature(const CFSocketSignature
*providedSignature
, CFSocketSignature
*signature
, uint16_t defaultPortNumber
) {
3358 struct sockaddr_in sain
, *sainp
;
3359 memset(&sain
, 0, sizeof(sain
));
3360 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
3361 sain
.sin_len
= sizeof(sain
);
3363 sain
.sin_family
= AF_INET
;
3364 sain
.sin_port
= htons(__CFSocketDefaultNameRegistryPortNumber
);
3365 sain
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
3366 if (NULL
== providedSignature
) {
3367 signature
->protocolFamily
= PF_INET
;
3368 signature
->socketType
= SOCK_STREAM
;
3369 signature
->protocol
= IPPROTO_TCP
;
3370 signature
->address
= CFDataCreate(kCFAllocatorSystemDefault
, (uint8_t *)&sain
, sizeof(sain
));
3372 signature
->protocolFamily
= providedSignature
->protocolFamily
;
3373 signature
->socketType
= providedSignature
->socketType
;
3374 signature
->protocol
= providedSignature
->protocol
;
3375 if (0 >= signature
->protocolFamily
) signature
->protocolFamily
= PF_INET
;
3376 if (PF_INET
== signature
->protocolFamily
) {
3377 if (0 >= signature
->socketType
) signature
->socketType
= SOCK_STREAM
;
3378 if (0 >= signature
->protocol
&& SOCK_STREAM
== signature
->socketType
) signature
->protocol
= IPPROTO_TCP
;
3379 if (0 >= signature
->protocol
&& SOCK_DGRAM
== signature
->socketType
) signature
->protocol
= IPPROTO_UDP
;
3381 if (NULL
== providedSignature
->address
) {
3382 signature
->address
= CFDataCreate(kCFAllocatorSystemDefault
, (uint8_t *)&sain
, sizeof(sain
));
3384 sainp
= (struct sockaddr_in
*)CFDataGetBytePtr(providedSignature
->address
);
3385 if ((int)sizeof(struct sockaddr_in
) <= CFDataGetLength(providedSignature
->address
) && (AF_INET
== sainp
->sin_family
|| 0 == sainp
->sin_family
)) {
3386 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
3387 sain
.sin_len
= sizeof(sain
);
3389 sain
.sin_family
= AF_INET
;
3390 sain
.sin_port
= sainp
->sin_port
;
3391 if (0 == sain
.sin_port
) sain
.sin_port
= htons(defaultPortNumber
);
3392 sain
.sin_addr
.s_addr
= sainp
->sin_addr
.s_addr
;
3393 if (htonl(INADDR_ANY
) == sain
.sin_addr
.s_addr
) sain
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
3394 signature
->address
= CFDataCreate(kCFAllocatorSystemDefault
, (uint8_t *)&sain
, sizeof(sain
));
3396 signature
->address
= (CFDataRef
)CFRetain(providedSignature
->address
);
3402 CFSocketError
CFSocketRegisterValue(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
, CFPropertyListRef value
) {
3403 CFSocketSignature signature
;
3404 CFMutableDictionaryRef dictionary
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 3, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
3405 CFSocketError retval
= kCFSocketError
;
3406 __CFSocketNameRegistryResponse response
= {&retval
, NULL
, NULL
};
3407 CFDictionaryAddValue(dictionary
, kCFSocketCommandKey
, kCFSocketRegisterCommand
);
3408 CFDictionaryAddValue(dictionary
, kCFSocketNameKey
, name
);
3409 if (NULL
!= value
) CFDictionaryAddValue(dictionary
, kCFSocketValueKey
, value
);
3410 __CFSocketValidateSignature(nameServerSignature
, &signature
, __CFSocketDefaultNameRegistryPortNumber
);
3411 __CFSocketSendNameRegistryRequest(&signature
, dictionary
, &response
, timeout
);
3412 CFRelease(dictionary
);
3413 CFRelease(signature
.address
);
3417 CFSocketError
CFSocketCopyRegisteredValue(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
, CFPropertyListRef
*value
, CFDataRef
*serverAddress
) {
3418 CFSocketSignature signature
;
3419 CFMutableDictionaryRef dictionary
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 2, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
3420 CFSocketError retval
= kCFSocketError
;
3421 __CFSocketNameRegistryResponse response
= {&retval
, value
, serverAddress
};
3422 CFDictionaryAddValue(dictionary
, kCFSocketCommandKey
, kCFSocketRetrieveCommand
);
3423 CFDictionaryAddValue(dictionary
, kCFSocketNameKey
, name
);
3424 __CFSocketValidateSignature(nameServerSignature
, &signature
, __CFSocketDefaultNameRegistryPortNumber
);
3425 __CFSocketSendNameRegistryRequest(&signature
, dictionary
, &response
, timeout
);
3426 CFRelease(dictionary
);
3427 CFRelease(signature
.address
);
3431 CFSocketError
CFSocketRegisterSocketSignature(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
, const CFSocketSignature
*signature
) {
3432 CFSocketSignature validatedSignature
;
3433 CFMutableDataRef data
= NULL
;
3434 CFSocketError retval
;
3437 if (NULL
== signature
) {
3438 retval
= CFSocketUnregister(nameServerSignature
, timeout
, name
);
3440 __CFSocketValidateSignature(signature
, &validatedSignature
, 0);
3441 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
) {
3442 retval
= kCFSocketError
;
3444 data
= CFDataCreateMutable(kCFAllocatorSystemDefault
, sizeof(bytes
) + length
);
3445 bytes
[0] = validatedSignature
.protocolFamily
;
3446 bytes
[1] = validatedSignature
.socketType
;
3447 bytes
[2] = validatedSignature
.protocol
;
3449 CFDataAppendBytes(data
, bytes
, sizeof(bytes
));
3450 CFDataAppendBytes(data
, CFDataGetBytePtr(validatedSignature
.address
), length
);
3451 retval
= CFSocketRegisterValue(nameServerSignature
, timeout
, name
, data
);
3454 CFRelease(validatedSignature
.address
);
3459 CFSocketError
CFSocketCopyRegisteredSocketSignature(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
, CFSocketSignature
*signature
, CFDataRef
*nameServerAddress
) {
3460 CFDataRef data
= NULL
;
3461 CFSocketSignature returnedSignature
;
3462 const uint8_t *ptr
= NULL
, *aptr
= NULL
;
3465 CFDataRef serverAddress
= NULL
;
3466 CFSocketError retval
= CFSocketCopyRegisteredValue(nameServerSignature
, timeout
, name
, (CFPropertyListRef
*)&data
, &serverAddress
);
3467 if (NULL
== data
|| CFGetTypeID(data
) != CFDataGetTypeID() || NULL
== (ptr
= CFDataGetBytePtr(data
)) || (length
= CFDataGetLength(data
)) < 4) retval
= kCFSocketError
;
3468 if (kCFSocketSuccess
== retval
&& NULL
!= signature
) {
3469 returnedSignature
.protocolFamily
= (SInt32
)*ptr
++;
3470 returnedSignature
.socketType
= (SInt32
)*ptr
++;
3471 returnedSignature
.protocol
= (SInt32
)*ptr
++;
3473 returnedSignature
.address
= CFDataCreate(kCFAllocatorSystemDefault
, ptr
, length
- 4);
3474 __CFSocketValidateSignature(&returnedSignature
, signature
, 0);
3475 CFRelease(returnedSignature
.address
);
3476 ptr
= CFDataGetBytePtr(signature
->address
);
3477 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
) {
3478 CFMutableDataRef address
= CFDataCreateMutableCopy(kCFAllocatorSystemDefault
, CFDataGetLength(signature
->address
), signature
->address
);
3479 mptr
= CFDataGetMutableBytePtr(address
);
3480 ((struct sockaddr_in
*)mptr
)->sin_addr
= ((struct sockaddr_in
*)aptr
)->sin_addr
;
3481 CFRelease(signature
->address
);
3482 signature
->address
= address
;
3484 if (NULL
!= nameServerAddress
) *nameServerAddress
= serverAddress
? (CFDataRef
)CFRetain(serverAddress
) : NULL
;
3486 if (NULL
!= data
) CFRelease(data
);
3487 if (NULL
!= serverAddress
) CFRelease(serverAddress
);
3491 CFSocketError
CFSocketUnregister(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
) {
3492 return CFSocketRegisterValue(nameServerSignature
, timeout
, name
, NULL
);
3495 CF_EXPORT
void CFSocketSetDefaultNameRegistryPortNumber(uint16_t port
) {
3496 __CFSocketDefaultNameRegistryPortNumber
= port
;
3499 CF_EXPORT
uint16_t CFSocketGetDefaultNameRegistryPortNumber(void) {
3500 return __CFSocketDefaultNameRegistryPortNumber
;