2 * Copyright (c) 2011 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-2011, Apple Inc. All rights reserved.
26 Responsibility: Christopher Kane
34 #include <CoreFoundation/CFSocket.h>
35 #include "CFInternal.h"
36 #include <dispatch/dispatch.h>
37 #include <netinet/in.h>
38 #include <sys/sysctl.h>
39 #include <sys/socket.h>
40 #include <sys/ioctl.h>
44 #include <sys/select.h>
47 extern void _CFRunLoopSourceWakeUpRunLoops(CFRunLoopSourceRef rls);
49 #define INVALID_SOCKET (CFSocketNativeHandle)(-1)
50 #define MAX_SOCKADDR_LEN 256
53 DISPATCH_HELPER_FUNCTIONS(sock, CFSocket)
55 static Boolean sockfd_is_readable(int fd) {
56 if (fd < 0 || 1048576 <= fd) HALT;
57 size_t sz = ((fd + CHAR_BIT) / CHAR_BIT) + 7; // generous
58 fd_set *fdset = malloc(sz);
63 struct timespec ts = {0, 1000UL}; // 1 us
64 ret = pselect(fd + 1, fdset, NULL, NULL, &ts, NULL);
65 } while (ret < 0 && (EINTR == errno || EAGAIN == errno));
66 Boolean isSet = ((0 < ret) && FD_ISSET(fd, fdset));
71 static Boolean sockfd_is_writeable(int fd) {
72 if (fd < 0 || 1048576 <= fd) HALT;
73 size_t sz = ((fd + CHAR_BIT) / CHAR_BIT) + 7; // generous
74 fd_set *fdset = malloc(sz);
79 struct timespec ts = {0, 1000UL}; // 1 us
80 ret = pselect(fd + 1, NULL, fdset, NULL, &ts, NULL);
81 } while (ret < 0 && (EINTR == errno || EAGAIN == errno));
82 Boolean isSet = ((0 < ret) && FD_ISSET(fd, fdset));
89 kCFSocketStateReady = 0,
90 kCFSocketStateInvalidating = 1,
91 kCFSocketStateInvalid = 2,
92 kCFSocketStateDeallocating = 3
95 struct __shared_blob {
96 dispatch_source_t _rdsrc;
97 dispatch_source_t _wrsrc;
98 CFRunLoopSourceRef _source;
99 CFSocketNativeHandle _socket;
106 struct __shared_blob *_shared; // non-NULL when valid, NULL when invalid
108 uint8_t _state:2; // mutable, not written safely
109 uint8_t _isSaneFD:1; // immutable
110 uint8_t _connOriented:1; // immutable
111 uint8_t _wantConnect:1; // immutable
112 uint8_t _wantWrite:1; // immutable
113 uint8_t _wantReadType:2; // immutable
117 uint8_t _rsuspended:1;
118 uint8_t _wsuspended:1;
120 uint8_t _writeable:1;
123 uint8_t _reenableRead:1;
124 uint8_t _readDisabled:1;
125 uint8_t _reenableWrite:1;
126 uint8_t _writeDisabled:1;
127 uint8_t _connectDisabled:1;
128 uint8_t _connected:1;
129 uint8_t _leaveErrors:1;
130 uint8_t _closeOnInvalidate:1;
132 int32_t _runLoopCounter;
134 CFDataRef _address; // immutable, once created
135 CFDataRef _peerAddress; // immutable, once created
136 CFSocketCallBack _callout; // immutable
137 CFSocketContext _context; // immutable
141 CF_INLINE Boolean __CFSocketIsValid(CFSocketRef sock) {
142 return kCFSocketStateReady == sock->_state;
145 static CFStringRef __CFSocketCopyDescription(CFTypeRef cf) {
146 CFSocketRef sock = (CFSocketRef)cf;
147 CFStringRef contextDesc = NULL;
148 if (NULL != sock->_context.info && NULL != sock->_context.copyDescription) {
149 contextDesc = sock->_context.copyDescription(sock->_context.info);
151 if (NULL == contextDesc) {
152 contextDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFSocket context %p>"), sock->_context.info);
155 void *addr = sock->_callout;
156 const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???";
158 ioctlsocket(sock->_shared ? sock->_shared->_socket : -1, FIONREAD, &avail);
159 CFStringRef result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR(
160 "<CFSocket %p [%p]>{valid = %s, socket = %d, "
161 "want connect = %s, connect disabled = %s, "
162 "want write = %s, reenable write = %s, write disabled = %s, "
163 "want read = %s, reenable read = %s, read disabled = %s, "
164 "leave errors = %s, close on invalidate = %s, connected = %s, "
165 "last error code = %d, bytes available for read = %d, "
166 "source = %p, callout = %s (%p), context = %@}"),
167 cf, CFGetAllocator(sock), __CFSocketIsValid(sock) ? "Yes" : "No", sock->_shared ? sock->_shared->_socket : -1,
168 sock->_wantConnect ? "Yes" : "No", sock->_connectDisabled ? "Yes" : "No",
169 sock->_wantWrite ? "Yes" : "No", sock->_reenableWrite ? "Yes" : "No", sock->_writeDisabled ? "Yes" : "No",
170 sock->_wantReadType ? "Yes" : "No", sock->_reenableRead ? "Yes" : "No", sock->_readDisabled? "Yes" : "No",
171 sock->_leaveErrors ? "Yes" : "No", sock->_closeOnInvalidate ? "Yes" : "No", sock->_connected ? "Yes" : "No",
173 sock->_shared ? sock->_shared->_source : NULL, name, addr, contextDesc);
174 if (NULL != contextDesc) {
175 CFRelease(contextDesc);
180 static void __CFSocketDeallocate(CFTypeRef cf) {
181 CHECK_FOR_FORK_RET();
182 CFSocketRef sock = (CFSocketRef)cf;
183 // Since CFSockets are cached, we can only get here sometime after being invalidated
184 sock->_state = kCFSocketStateDeallocating;
185 if (sock->_peerAddress) {
186 CFRelease(sock->_peerAddress);
187 sock->_peerAddress = NULL;
189 if (sock->_address) {
190 CFRelease(sock->_address);
191 sock->_address = NULL;
195 static CFTypeID __kCFSocketTypeID = _kCFRuntimeNotATypeID;
197 static const CFRuntimeClass __CFSocketClass = {
202 __CFSocketDeallocate,
206 __CFSocketCopyDescription
209 static CFMutableArrayRef __CFAllSockets = NULL;
211 CFTypeID CFSocketGetTypeID(void) {
212 if (_kCFRuntimeNotATypeID == __kCFSocketTypeID) {
213 __kCFSocketTypeID = _CFRuntimeRegisterClass(&__CFSocketClass);
214 __CFAllSockets = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
216 int ret1 = getrlimit(RLIMIT_NOFILE, &lim1);
217 int mib[] = {CTL_KERN, KERN_MAXFILESPERPROC};
219 size_t len = sizeof(int);
220 int ret0 = sysctl(mib, 2, &maxfd, &len, NULL, 0);
221 if (0 == ret0 && 0 == ret1 && lim1.rlim_max < maxfd) maxfd = lim1.rlim_max;
222 if (0 == ret1 && lim1.rlim_cur < maxfd) {
223 struct rlimit lim2 = lim1;
224 lim2.rlim_cur += 2304;
225 if (maxfd < lim2.rlim_cur) lim2.rlim_cur = maxfd;
226 setrlimit(RLIMIT_NOFILE, &lim2);
227 // we try, but do not go to extraordinary measures
230 return __kCFSocketTypeID;
233 CFSocketRef CFSocketCreateWithNative(CFAllocatorRef allocator, CFSocketNativeHandle ufd, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context) {
234 CHECK_FOR_FORK_RET(NULL);
236 CFSocketGetTypeID(); // cause initialization if necessary
239 int ret = fstat(ufd, &statbuf);
240 if (ret < 0) ufd = INVALID_SOCKET;
242 Boolean sane = false;
243 if (INVALID_SOCKET != ufd) {
244 uint32_t type = (statbuf.st_mode & S_IFMT);
245 sane = (S_IFSOCK == type) || (S_IFIFO == type) || (S_IFCHR == type);
247 CFLog(kCFLogLevelWarning, CFSTR("*** CFSocketCreateWithNative(): creating CFSocket with silly fd type (%07o) -- may or may not work"), type);
251 if (INVALID_SOCKET != ufd) {
252 Boolean canHandle = false;
253 int tmp_kq = kqueue();
256 EV_SET(&ev[0], ufd, EVFILT_READ, EV_ADD, 0, 0, 0);
257 EV_SET(&ev[1], ufd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
258 int ret = kevent(tmp_kq, ev, 2, NULL, 0, NULL);
259 canHandle = (0 <= ret); // if kevent(ADD) succeeds, can handle
262 if (1 && !canHandle) {
263 CFLog(kCFLogLevelWarning, CFSTR("*** CFSocketCreateWithNative(): creating CFSocket with unsupported fd type -- may or may not work"));
267 if (INVALID_SOCKET == ufd) {
268 // Historically, bad ufd was allowed, but gave an uncached and already-invalid CFSocketRef
269 SInt32 size = sizeof(struct __CFSocket) - sizeof(CFRuntimeBase);
270 CFSocketRef memory = (CFSocketRef)_CFRuntimeCreateInstance(allocator, CFSocketGetTypeID(), size, NULL);
271 if (NULL == memory) {
274 memory->_callout = callout;
275 memory->_state = kCFSocketStateInvalid;
279 __block CFSocketRef sock = NULL;
280 dispatch_sync(__sockQueue(), ^{
281 for (CFIndex idx = 0, cnt = CFArrayGetCount(__CFAllSockets); idx < cnt; idx++) {
282 CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(__CFAllSockets, idx);
283 if (s->_shared->_socket == ufd) {
290 SInt32 size = sizeof(struct __CFSocket) - sizeof(CFRuntimeBase);
291 CFSocketRef memory = (CFSocketRef)_CFRuntimeCreateInstance(allocator, CFSocketGetTypeID(), size, NULL);
292 if (NULL == memory) {
297 if (INVALID_SOCKET != ufd) {
298 socklen_t typeSize = sizeof(socketType);
299 int ret = getsockopt(ufd, SOL_SOCKET, SO_TYPE, (void *)&socketType, (socklen_t *)&typeSize);
300 if (ret < 0) socketType = 0;
303 memory->_rsuspended = true;
304 memory->_wsuspended = true;
305 memory->_readable = false;
306 memory->_writeable = false;
308 memory->_isSaneFD = sane ? 1 : 0;
309 memory->_wantReadType = (callBackTypes & 0x3);
310 memory->_reenableRead = memory->_wantReadType ? true : false;
311 memory->_readDisabled = false;
312 memory->_wantWrite = (callBackTypes & kCFSocketWriteCallBack) ? true : false;
313 memory->_reenableWrite = false;
314 memory->_writeDisabled = false;
315 memory->_wantConnect = (callBackTypes & kCFSocketConnectCallBack) ? true : false;
316 memory->_connectDisabled = false;
317 memory->_leaveErrors = false;
318 memory->_closeOnInvalidate = true;
319 memory->_connOriented = (SOCK_STREAM == socketType || SOCK_SEQPACKET == socketType);
320 memory->_connected = (memory->_wantReadType == kCFSocketAcceptCallBack || !memory->_connOriented) ? true : false;
323 memory->_runLoopCounter = 0;
324 memory->_address = NULL;
325 memory->_peerAddress = NULL;
326 memory->_context.info = NULL;
327 memory->_context.retain = NULL;
328 memory->_context.release = NULL;
329 memory->_context.copyDescription = NULL;
330 memory->_callout = callout;
331 if (NULL != context) {
332 objc_memmove_collectable(&memory->_context, context, sizeof(CFSocketContext));
333 memory->_context.info = context->retain ? (void *)context->retain(context->info) : context->info;
336 struct __shared_blob *shared = malloc(sizeof(struct __shared_blob));
337 shared->_rdsrc = NULL;
338 shared->_wrsrc = NULL;
339 shared->_source = NULL;
340 shared->_socket = ufd;
341 shared->_closeFD = true; // copy of _closeOnInvalidate
342 shared->_refCnt = 1; // one for the CFSocket
343 memory->_shared = shared;
345 if (memory->_wantReadType) {
346 dispatch_source_t dsrc = NULL;
348 dsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, ufd, 0, __sockQueue());
350 dsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, __sockQueue());
351 dispatch_source_set_timer(dsrc, dispatch_time(DISPATCH_TIME_NOW, 0), NSEC_PER_SEC / 2, NSEC_PER_SEC);
353 dispatch_block_t event_block = ^{
354 memory->_readable = true;
355 if (!memory->_rsuspended) {
356 dispatch_suspend(dsrc);
357 // CFLog(5, CFSTR("suspend %p due to read event block"), memory);
358 memory->_rsuspended = true;
360 if (shared->_source) {
361 CFRunLoopSourceSignal(shared->_source);
362 _CFRunLoopSourceWakeUpRunLoops(shared->_source);
365 dispatch_block_t cancel_block = ^{
366 shared->_rdsrc = NULL;
368 if (0 == shared->_refCnt) {
369 if (shared->_closeFD) {
370 // thoroughly stop anything else from using the fd
371 (void)shutdown(shared->_socket, SHUT_RDWR);
372 int nullfd = open("/dev/null", O_RDONLY);
373 dup2(nullfd, shared->_socket);
375 close(shared->_socket);
379 dispatch_release(dsrc);
381 dispatch_source_set_event_handler(dsrc, event_block);
382 dispatch_source_set_cancel_handler(dsrc, cancel_block);
383 shared->_rdsrc = dsrc;
385 if (memory->_wantWrite || memory->_wantConnect) {
386 dispatch_source_t dsrc = NULL;
388 dsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, ufd, 0, __sockQueue());
390 dsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, __sockQueue());
391 dispatch_source_set_timer(dsrc, dispatch_time(DISPATCH_TIME_NOW, 0), NSEC_PER_SEC / 2, NSEC_PER_SEC);
393 dispatch_block_t event_block = ^{
394 memory->_writeable = true;
395 if (!memory->_wsuspended) {
396 dispatch_suspend(dsrc);
397 // CFLog(5, CFSTR("suspend %p due to write event block"), memory);
398 memory->_wsuspended = true;
400 if (shared->_source) {
401 CFRunLoopSourceSignal(shared->_source);
402 _CFRunLoopSourceWakeUpRunLoops(shared->_source);
405 dispatch_block_t cancel_block = ^{
406 shared->_wrsrc = NULL;
408 if (0 == shared->_refCnt) {
409 if (shared->_closeFD) {
410 // thoroughly stop anything else from using the fd
411 (void)shutdown(shared->_socket, SHUT_RDWR);
412 int nullfd = open("/dev/null", O_RDONLY);
413 dup2(nullfd, shared->_socket);
415 close(shared->_socket);
419 dispatch_release(dsrc);
421 dispatch_source_set_event_handler(dsrc, event_block);
422 dispatch_source_set_cancel_handler(dsrc, cancel_block);
423 shared->_wrsrc = dsrc;
426 if (shared->_rdsrc) {
429 if (shared->_wrsrc) {
433 memory->_state = kCFSocketStateReady;
434 CFArrayAppendValue(__CFAllSockets, memory);
437 // CFLog(5, CFSTR("CFSocketCreateWithNative(): created socket %p with callbacks 0x%x"), sock, callBackTypes);
438 if (sock && !CFSocketIsValid(sock)) { // must do this outside lock to avoid deadlock
445 CFSocketNativeHandle CFSocketGetNative(CFSocketRef sock) {
446 CHECK_FOR_FORK_RET(INVALID_SOCKET);
447 __CFGenericValidateType(sock, CFSocketGetTypeID());
448 return sock->_shared ? sock->_shared->_socket : INVALID_SOCKET;
451 void CFSocketGetContext(CFSocketRef sock, CFSocketContext *context) {
452 __CFGenericValidateType(sock, CFSocketGetTypeID());
453 CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__);
454 objc_memmove_collectable(context, &sock->_context, sizeof(CFSocketContext));
457 CFDataRef CFSocketCopyAddress(CFSocketRef sock) {
458 CHECK_FOR_FORK_RET(NULL);
459 __CFGenericValidateType(sock, CFSocketGetTypeID());
460 __block CFDataRef result = NULL;
461 dispatch_sync(__sockQueue(), ^{
462 if (!sock->_address) {
463 if (!__CFSocketIsValid(sock)) return;
464 uint8_t name[MAX_SOCKADDR_LEN];
465 socklen_t namelen = sizeof(name);
466 int ret = getsockname(sock->_shared->_socket, (struct sockaddr *)name, (socklen_t *)&namelen);
467 if (0 == ret && 0 < namelen) {
468 sock->_address = CFDataCreate(CFGetAllocator(sock), name, namelen);
471 result = sock->_address ? (CFDataRef)CFRetain(sock->_address) : NULL;
476 CFDataRef CFSocketCopyPeerAddress(CFSocketRef sock) {
477 CHECK_FOR_FORK_RET(NULL);
478 __CFGenericValidateType(sock, CFSocketGetTypeID());
479 __block CFDataRef result = NULL;
480 dispatch_sync(__sockQueue(), ^{
481 if (!sock->_peerAddress) {
482 if (!__CFSocketIsValid(sock)) return;
483 uint8_t name[MAX_SOCKADDR_LEN];
484 socklen_t namelen = sizeof(name);
485 int ret = getpeername(sock->_shared->_socket, (struct sockaddr *)name, (socklen_t *)&namelen);
486 if (0 == ret && 0 < namelen) {
487 sock->_peerAddress = CFDataCreate(CFGetAllocator(sock), name, namelen);
490 result = sock->_peerAddress ? (CFDataRef)CFRetain(sock->_peerAddress) : NULL;
495 CFOptionFlags CFSocketGetSocketFlags(CFSocketRef sock) {
497 __CFGenericValidateType(sock, CFSocketGetTypeID());
498 __block CFOptionFlags flags = 0;
499 dispatch_sync(__sockQueue(), ^{
500 if (sock->_reenableRead) flags |= sock->_wantReadType; // flags are same as types here
501 if (sock->_reenableWrite) flags |= kCFSocketAutomaticallyReenableWriteCallBack;
502 if (sock->_leaveErrors) flags |= kCFSocketLeaveErrors;
503 if (sock->_closeOnInvalidate) flags |= kCFSocketCloseOnInvalidate;
508 void CFSocketSetSocketFlags(CFSocketRef sock, CFOptionFlags flags) {
510 // CFLog(5, CFSTR("CFSocketSetSocketFlags(%p, 0x%x) starting"), sock, flags);
511 __CFGenericValidateType(sock, CFSocketGetTypeID());
512 dispatch_sync(__sockQueue(), ^{
513 sock->_reenableRead = (sock->_wantReadType && ((flags & 0x3) == sock->_wantReadType)) ? true : false;
514 sock->_reenableWrite = (sock->_wantWrite && (flags & kCFSocketAutomaticallyReenableWriteCallBack)) ? true : false;
515 sock->_leaveErrors = (flags & kCFSocketLeaveErrors) ? true : false;
516 sock->_closeOnInvalidate = (flags & kCFSocketCloseOnInvalidate) ? true : false;
517 if (sock->_shared) sock->_shared->_closeFD = sock->_closeOnInvalidate;
519 // CFLog(5, CFSTR("CFSocketSetSocketFlags(%p, 0x%x) done"), sock, flags);
522 void CFSocketEnableCallBacks(CFSocketRef sock, CFOptionFlags callBackTypes) {
523 CHECK_FOR_FORK_RET();
524 __CFGenericValidateType(sock, CFSocketGetTypeID());
525 // CFLog(5, CFSTR("CFSocketEnableCallBacks(%p, 0x%x) starting"), sock, callBackTypes);
526 dispatch_sync(__sockQueue(), ^{
527 if (!__CFSocketIsValid(sock)) return;
528 if (sock->_wantReadType && (callBackTypes & 0x3) == sock->_wantReadType) {
529 if (sockfd_is_readable(sock->_shared->_socket)) {
530 sock->_readable = true;
531 // CFLog(5, CFSTR("CFSocketEnableCallBacks(%p, 0x%x) socket is readable"), sock, callBackTypes);
532 if (!sock->_rsuspended) {
533 dispatch_suspend(sock->_shared->_rdsrc);
534 sock->_rsuspended = true;
536 // If the source exists, but is now invalid, this next stuff is relatively harmless.
537 if (sock->_shared->_source) {
538 CFRunLoopSourceSignal(sock->_shared->_source);
539 _CFRunLoopSourceWakeUpRunLoops(sock->_shared->_source);
541 } else if (sock->_rsuspended && sock->_shared->_rdsrc) {
542 sock->_rsuspended = false;
543 dispatch_resume(sock->_shared->_rdsrc);
545 sock->_readDisabled = false;
547 if (sock->_wantWrite && (callBackTypes & kCFSocketWriteCallBack)) {
548 if (sockfd_is_writeable(sock->_shared->_socket)) {
549 sock->_writeable = true;
550 if (!sock->_wsuspended) {
551 dispatch_suspend(sock->_shared->_wrsrc);
552 sock->_wsuspended = true;
554 // If the source exists, but is now invalid, this next stuff is relatively harmless.
555 if (sock->_shared->_source) {
556 CFRunLoopSourceSignal(sock->_shared->_source);
557 _CFRunLoopSourceWakeUpRunLoops(sock->_shared->_source);
559 } else if (sock->_wsuspended && sock->_shared->_wrsrc) {
560 sock->_wsuspended = false;
561 dispatch_resume(sock->_shared->_wrsrc);
563 sock->_writeDisabled = false;
565 if (sock->_wantConnect && !sock->_connected && (callBackTypes & kCFSocketConnectCallBack)) {
566 if (sockfd_is_writeable(sock->_shared->_socket)) {
567 sock->_writeable = true;
568 if (!sock->_wsuspended) {
569 dispatch_suspend(sock->_shared->_wrsrc);
570 sock->_wsuspended = true;
572 // If the source exists, but is now invalid, this next stuff is relatively harmless.
573 if (sock->_shared->_source) {
574 CFRunLoopSourceSignal(sock->_shared->_source);
575 _CFRunLoopSourceWakeUpRunLoops(sock->_shared->_source);
577 } else if (sock->_wsuspended && sock->_shared->_wrsrc) {
578 sock->_wsuspended = false;
579 dispatch_resume(sock->_shared->_wrsrc);
581 sock->_connectDisabled = false;
584 // CFLog(5, CFSTR("CFSocketEnableCallBacks(%p, 0x%x) done"), sock, callBackTypes);
587 void CFSocketDisableCallBacks(CFSocketRef sock, CFOptionFlags callBackTypes) {
588 CHECK_FOR_FORK_RET();
589 __CFGenericValidateType(sock, CFSocketGetTypeID());
590 // CFLog(5, CFSTR("CFSocketDisableCallBacks(%p, 0x%x) starting"), sock, callBackTypes);
591 dispatch_sync(__sockQueue(), ^{
592 if (!__CFSocketIsValid(sock)) return;
593 if (sock->_wantReadType && (callBackTypes & 0x3) == sock->_wantReadType) {
594 if (!sock->_rsuspended && sock->_shared->_rdsrc) {
595 dispatch_suspend(sock->_shared->_rdsrc);
596 sock->_rsuspended = true;
598 sock->_readDisabled = true;
600 if (sock->_wantWrite && (callBackTypes & kCFSocketWriteCallBack)) {
601 if (!sock->_wsuspended && sock->_shared->_wrsrc) {
602 dispatch_suspend(sock->_shared->_wrsrc);
603 sock->_wsuspended = true;
605 sock->_writeDisabled = true;
607 if (sock->_wantConnect && !sock->_connected && (callBackTypes & kCFSocketConnectCallBack)) {
608 if (!sock->_wsuspended && sock->_shared->_wrsrc) {
609 dispatch_suspend(sock->_shared->_wrsrc);
610 sock->_wsuspended = true;
612 sock->_connectDisabled = true;
615 // CFLog(5, CFSTR("CFSocketDisableCallBacks(%p, 0x%x) done"), sock, callBackTypes);
618 void CFSocketInvalidate(CFSocketRef sock) {
619 CHECK_FOR_FORK_RET();
620 __CFGenericValidateType(sock, CFSocketGetTypeID());
622 // CFLog(5, CFSTR("CFSocketInvalidate(%p) starting"), sock);
623 __block CFRunLoopSourceRef source = NULL;
624 __block Boolean wasReady = false;
625 dispatch_sync(__sockQueue(), ^{
626 wasReady = (sock->_state == kCFSocketStateReady);
628 sock->_state = kCFSocketStateInvalidating;
630 for (CFIndex idx = 0, cnt = CFArrayGetCount(__CFAllSockets); idx < cnt; idx++) {
631 CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(__CFAllSockets, idx);
633 CFArrayRemoveValueAtIndex(__CFAllSockets, idx);
637 if (sock->_shared->_rdsrc) {
638 dispatch_source_cancel(sock->_shared->_rdsrc);
639 if (sock->_rsuspended) {
640 sock->_rsuspended = false;
641 dispatch_resume(sock->_shared->_rdsrc);
644 if (sock->_shared->_wrsrc) {
645 dispatch_source_cancel(sock->_shared->_wrsrc);
646 if (sock->_wsuspended) {
647 sock->_wsuspended = false;
648 dispatch_resume(sock->_shared->_wrsrc);
651 source = sock->_shared->_source;
652 sock->_shared->_source = NULL;
653 sock->_shared->_refCnt--;
654 if (0 == sock->_shared->_refCnt) {
655 if (sock->_shared->_closeFD) {
656 // thoroughly stop anything else from using the fd
657 (void)shutdown(sock->_shared->_socket, SHUT_RDWR);
658 int nullfd = open("/dev/null", O_RDONLY);
659 dup2(nullfd, sock->_shared->_socket);
661 close(sock->_shared->_socket);
665 sock->_shared = NULL;
669 if (NULL != source) {
670 CFRunLoopSourceInvalidate(source);
673 void *info = sock->_context.info;
674 sock->_context.info = NULL;
675 if (sock->_context.release) {
676 sock->_context.release(info);
678 sock->_state = kCFSocketStateInvalid;
681 // CFLog(5, CFSTR("CFSocketInvalidate(%p) done%s"), sock, wasReady ? " -- done on this thread" : "");
685 Boolean CFSocketIsValid(CFSocketRef sock) {
686 __CFGenericValidateType(sock, CFSocketGetTypeID());
687 if (!__CFSocketIsValid(sock)) return false;
689 int ret = sock->_shared ? fstat(sock->_shared->_socket, &statbuf) : -1;
691 CFSocketInvalidate(sock);
698 static void __CFSocketPerform(void *info) { // CFRunLoop should only call this on one thread at a time
699 CHECK_FOR_FORK_RET();
700 CFSocketRef sock = (CFSocketRef)info;
702 // CFLog(5, CFSTR("__CFSocketPerform(%p) starting '%@'"), sock, sock);
703 __block Boolean doRead = false, doWrite = false, doConnect = false, isValid = false;
704 __block int fd = INVALID_SOCKET;
705 __block SInt32 errorCode = 0;
706 __block int new_fd = INVALID_SOCKET;
707 __block CFDataRef address = NULL;
708 __block CFMutableDataRef data = NULL;
709 __block void *context_info = NULL;
710 __block void (*context_release)(const void *) = NULL;
711 dispatch_sync(__sockQueue(), ^{
712 isValid = __CFSocketIsValid(sock);
713 if (!isValid) return;
714 fd = sock->_shared->_socket;
715 doRead = sock->_readable && sock->_wantReadType && !sock->_readDisabled;
717 sock->_readable = false;
718 doRead = sockfd_is_readable(fd);
719 // if (!doRead) CFLog(5, CFSTR("__CFSocketPerform(%p) socket is not actually readable"), sock);
721 doWrite = sock->_writeable && sock->_wantWrite && !sock->_writeDisabled;
722 doConnect = sock->_writeable && sock->_wantConnect && !sock->_connectDisabled && !sock->_connected;
723 if (doWrite || doConnect) {
724 sock->_writeable = false;
725 if (doWrite) doWrite = sockfd_is_writeable(fd);
726 if (doConnect) doConnect = sockfd_is_writeable(fd);
728 if (!sock->_leaveErrors && (doWrite || doConnect)) { // not on read, for whatever reason
729 int errorSize = sizeof(errorCode);
730 int ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&errorCode, (socklen_t *)&errorSize);
731 if (0 != ret) errorCode = 0;
732 sock->_error = errorCode;
734 sock->_connected = true;
735 // CFLog(5, CFSTR("__CFSocketPerform(%p) doing %d %d %d"), sock, doRead, doWrite, doConnect);
737 switch (sock->_wantReadType) {
738 case kCFSocketReadCallBack:
740 case kCFSocketAcceptCallBack: {
741 uint8_t name[MAX_SOCKADDR_LEN];
742 socklen_t namelen = sizeof(name);
743 new_fd = accept(fd, (struct sockaddr *)name, (socklen_t *)&namelen);
744 if (INVALID_SOCKET != new_fd) {
745 address = CFDataCreate(CFGetAllocator(sock), name, namelen);
749 case kCFSocketDataCallBack: {
750 uint8_t name[MAX_SOCKADDR_LEN];
751 socklen_t namelen = sizeof(name);
753 int ret = ioctlsocket(fd, FIONREAD, &avail);
754 if (ret < 0 || avail < 256) avail = 256;
755 if ((1 << 20) < avail) avail = (1 << 20);
756 data = CFDataCreateMutable(CFGetAllocator(sock), 0);
757 CFDataSetLength(data, avail);
758 ssize_t len = recvfrom(fd, CFDataGetMutableBytePtr(data), avail, 0, (struct sockaddr *)name, (socklen_t *)&namelen);
759 CFIndex datalen = (len < 0) ? 0 : len;
760 CFDataSetLength(data, datalen);
762 address = CFDataCreate(CFGetAllocator(sock), name, namelen);
763 } else if (sock->_connOriented) {
764 // cannot call CFSocketCopyPeerAddress(), or deadlock
765 if (!sock->_peerAddress) {
766 uint8_t name[MAX_SOCKADDR_LEN];
767 socklen_t namelen = sizeof(name);
768 int ret = getpeername(sock->_shared->_socket, (struct sockaddr *)name, (socklen_t *)&namelen);
769 if (0 == ret && 0 < namelen) {
770 sock->_peerAddress = CFDataCreate(CFGetAllocator(sock), name, namelen);
773 address = sock->_peerAddress ? (CFDataRef)CFRetain(sock->_peerAddress) : NULL;
775 if (NULL == address) {
776 address = CFDataCreate(CFGetAllocator(sock), NULL, 0);
782 if (sock->_reenableRead) {
783 // CFLog(5, CFSTR("__CFSocketPerform(%p) reenabling read %d %p"), sock, sock->_rsuspended, sock->_shared->_rdsrc);
784 if (sock->_rsuspended && sock->_shared->_rdsrc) {
785 sock->_rsuspended = false;
786 dispatch_resume(sock->_shared->_rdsrc);
789 if (sock->_reenableWrite) {
790 if (sock->_wsuspended && sock->_shared->_wrsrc) {
791 sock->_wsuspended = false;
792 dispatch_resume(sock->_shared->_wrsrc);
795 if (sock->_context.retain && (doConnect || doRead || doWrite)) {
796 context_info = (void *)sock->_context.retain(sock->_context.info);
797 context_release = sock->_context.release;
799 context_info = sock->_context.info;
802 // CFLog(5, CFSTR("__CFSocketPerform(%p) isValid:%d, doRead:%d, doWrite:%d, doConnect:%d error:%d"), sock, isValid, doRead, doWrite, doConnect, errorCode);
803 if (!isValid || !(doConnect || doRead || doWrite)) return;
805 Boolean calledOut = false;
807 if (sock->_callout) sock->_callout(sock, kCFSocketConnectCallBack, NULL, (0 != errorCode) ? &errorCode : NULL, context_info);
810 if (doRead && (!calledOut || __CFSocketIsValid(sock))) {
811 switch (sock->_wantReadType) {
812 case kCFSocketReadCallBack:
813 if (sock->_callout) sock->_callout(sock, kCFSocketReadCallBack, NULL, NULL, context_info);
816 case kCFSocketAcceptCallBack:
817 if (INVALID_SOCKET != new_fd) {
818 if (sock->_callout) sock->_callout(sock, kCFSocketAcceptCallBack, address, &new_fd, context_info);
822 case kCFSocketDataCallBack:
823 if (sock->_callout) sock->_callout(sock, kCFSocketDataCallBack, address, data, context_info);
828 if (doWrite && (!calledOut || __CFSocketIsValid(sock))) {
829 if (0 == errorCode) {
830 if (sock->_callout) sock->_callout(sock, kCFSocketWriteCallBack, NULL, NULL, context_info);
835 if (data && 0 == CFDataGetLength(data)) CFSocketInvalidate(sock);
836 if (address) CFRelease(address);
837 if (data) CFRelease(data);
838 if (context_release) {
839 context_release(context_info);
842 CHECK_FOR_FORK_RET();
843 // CFLog(5, CFSTR("__CFSocketPerform(%p) done"), sock);
846 static void __CFSocketSchedule(void *info, CFRunLoopRef rl, CFStringRef mode) {
847 CFSocketRef sock = (CFSocketRef)info;
848 int32_t newVal = OSAtomicIncrement32Barrier(&sock->_runLoopCounter);
849 if (1 == newVal) { // on a transition from 0->1, the old code forced all desired callbacks enabled
850 CFOptionFlags types = sock->_wantReadType | (sock->_wantWrite ? kCFSocketWriteCallBack : 0) | (sock->_wantConnect ? kCFSocketConnectCallBack : 0);
851 CFSocketEnableCallBacks(sock, types);
856 static void __CFSocketCancel(void *info, CFRunLoopRef rl, CFStringRef mode) {
857 CFSocketRef sock = (CFSocketRef)info;
858 OSAtomicDecrement32Barrier(&sock->_runLoopCounter);
862 CFRunLoopSourceRef CFSocketCreateRunLoopSource(CFAllocatorRef allocator, CFSocketRef sock, CFIndex order) {
863 CHECK_FOR_FORK_RET(NULL);
864 __CFGenericValidateType(sock, CFSocketGetTypeID());
865 if (!CFSocketIsValid(sock)) return NULL;
866 __block CFRunLoopSourceRef result = NULL;
867 dispatch_sync(__sockQueue(), ^{
868 if (!__CFSocketIsValid(sock)) return;
869 if (NULL != sock->_shared->_source && !CFRunLoopSourceIsValid(sock->_shared->_source)) {
870 CFRelease(sock->_shared->_source);
871 sock->_shared->_source = NULL;
873 if (NULL == sock->_shared->_source) {
874 CFRunLoopSourceContext context;
876 context.info = (void *)sock;
877 context.retain = (const void *(*)(const void *))CFRetain;
878 context.release = (void (*)(const void *))CFRelease;
879 context.copyDescription = (CFStringRef (*)(const void *))__CFSocketCopyDescription;
880 context.equal = NULL;
882 context.schedule = __CFSocketSchedule;
883 context.cancel = __CFSocketCancel;
884 context.perform = __CFSocketPerform;
885 sock->_shared->_source = CFRunLoopSourceCreate(allocator, order, (CFRunLoopSourceContext *)&context);
886 if (sock->_shared->_source) {
887 if (sock->_wantReadType) {
888 if (sockfd_is_readable(sock->_shared->_socket)) {
889 sock->_readable = true;
890 if (!sock->_rsuspended) {
891 dispatch_suspend(sock->_shared->_rdsrc);
892 sock->_rsuspended = true;
894 if (sock->_shared->_source) {
895 CFRunLoopSourceSignal(sock->_shared->_source);
896 _CFRunLoopSourceWakeUpRunLoops(sock->_shared->_source);
898 } else if (sock->_rsuspended && sock->_shared->_rdsrc) {
899 sock->_rsuspended = false;
900 dispatch_resume(sock->_shared->_rdsrc);
903 if (sock->_wantWrite || (sock->_wantConnect && !sock->_connected)) {
904 if (sockfd_is_writeable(sock->_shared->_socket)) {
905 sock->_writeable = true;
906 if (!sock->_wsuspended) {
907 dispatch_suspend(sock->_shared->_wrsrc);
908 sock->_wsuspended = true;
910 if (sock->_shared->_source) {
911 CFRunLoopSourceSignal(sock->_shared->_source);
912 _CFRunLoopSourceWakeUpRunLoops(sock->_shared->_source);
914 } else if (sock->_wsuspended && sock->_shared->_wrsrc) {
915 sock->_wsuspended = false;
916 dispatch_resume(sock->_shared->_wrsrc);
921 result = sock->_shared->_source ? (CFRunLoopSourceRef)CFRetain(sock->_shared->_source) : NULL;
923 // CFLog(5, CFSTR("CFSocketCreateRunLoopSource(%p) => %p"), sock, result);
928 void __CFSocketSetSocketReadBufferAttrs(CFSocketRef s, CFTimeInterval timeout, CFIndex length) {
931 CFIndex __CFSocketRead(CFSocketRef s, UInt8* buffer, CFIndex length, int* error) {
933 int ret = read(CFSocketGetNative(s), buffer, length);
940 Boolean __CFSocketGetBytesAvailable(CFSocketRef s, CFIndex* ctBytesAvailable) {
942 int ret = ioctlsocket(CFSocketGetNative(s), FIONREAD, &bytesAvailable);
943 if (ret < 0) return false;
944 *ctBytesAvailable = (CFIndex)bytesAvailable;
949 #else /* not NEW_SOCKET */
952 #include <CoreFoundation/CFSocket.h>
953 #include <sys/types.h>
956 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
957 #include <sys/sysctl.h>
962 #include <CoreFoundation/CFArray.h>
963 #include <CoreFoundation/CFData.h>
964 #include <CoreFoundation/CFDictionary.h>
965 #include <CoreFoundation/CFRunLoop.h>
966 #include <CoreFoundation/CFString.h>
967 #include <CoreFoundation/CFPropertyList.h>
968 #include "CFInternal.h"
970 #if DEPLOYMENT_TARGET_WINDOWS
972 #define EINPROGRESS WSAEINPROGRESS
974 // redefine this to the winsock error in this file
976 #define EBADF WSAENOTSOCK
979 #define NFDBITS (sizeof(int32_t) * NBBY)
981 typedef int32_t fd_mask
;
982 typedef int socklen_t
;
984 // not entirely correct, but good enough for what it's used for here
985 void gettimeofday(struct timeval
*tp
, void *tzp
) {
990 // although this is only used for debug info, we define it for compatibility
991 #define timersub(tvp, uvp, vvp) \
993 (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
994 (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
995 if ((vvp)->tv_usec < 0) { \
997 (vvp)->tv_usec += 1000000; \
1002 #endif // DEPLOYMENT_TARGET_WINDOWS
1005 // On Mach we use a v0 RunLoopSource to make client callbacks. That source is signalled by a
1006 // separate SocketManager thread who uses select() to watch the sockets' fds.
1008 //#define LOG_CFSOCKET
1010 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1011 #define INVALID_SOCKET (CFSocketNativeHandle)(-1)
1012 #define closesocket(a) close((a))
1013 #define ioctlsocket(a,b,c) ioctl((a),(b),(c))
1016 CF_INLINE
int __CFSocketLastError(void) {
1017 #if DEPLOYMENT_TARGET_WINDOWS
1018 return WSAGetLastError();
1020 return thread_errno();
1024 CF_INLINE CFIndex
__CFSocketFdGetSize(CFDataRef fdSet
) {
1025 return NBBY
* CFDataGetLength(fdSet
);
1028 CF_INLINE Boolean
__CFSocketFdSet(CFSocketNativeHandle sock
, CFMutableDataRef fdSet
) {
1029 /* returns true if a change occurred, false otherwise */
1030 Boolean retval
= false;
1031 if (INVALID_SOCKET
!= sock
&& 0 <= sock
) {
1032 CFIndex numFds
= NBBY
* CFDataGetLength(fdSet
);
1034 if (sock
>= numFds
) {
1035 CFIndex oldSize
= numFds
/ NFDBITS
, newSize
= (sock
+ NFDBITS
) / NFDBITS
, changeInBytes
= (newSize
- oldSize
) * sizeof(fd_mask
);
1036 CFDataIncreaseLength(fdSet
, changeInBytes
);
1037 fds_bits
= (fd_mask
*)CFDataGetMutableBytePtr(fdSet
);
1038 memset(fds_bits
+ oldSize
, 0, changeInBytes
);
1040 fds_bits
= (fd_mask
*)CFDataGetMutableBytePtr(fdSet
);
1042 if (!FD_ISSET(sock
, (fd_set
*)fds_bits
)) {
1044 FD_SET(sock
, (fd_set
*)fds_bits
);
1051 #define MAX_SOCKADDR_LEN 256
1052 #define MAX_DATA_SIZE 65535
1053 #define MAX_CONNECTION_ORIENTED_DATA_SIZE 32768
1055 /* locks are to be acquired in the following order:
1056 (1) __CFAllSocketsLock
1057 (2) an individual CFSocket's lock
1058 (3) __CFActiveSocketsLock
1060 static CFSpinLock_t __CFAllSocketsLock
= CFSpinLockInit
; /* controls __CFAllSockets */
1061 static CFMutableDictionaryRef __CFAllSockets
= NULL
;
1062 static CFSpinLock_t __CFActiveSocketsLock
= CFSpinLockInit
; /* controls __CFRead/WriteSockets, __CFRead/WriteSocketsFds, __CFSocketManagerThread, and __CFSocketManagerIteration */
1063 static volatile UInt32 __CFSocketManagerIteration
= 0;
1064 static CFMutableArrayRef __CFWriteSockets
= NULL
;
1065 static CFMutableArrayRef __CFReadSockets
= NULL
;
1066 static CFMutableDataRef __CFWriteSocketsFds
= NULL
;
1067 static CFMutableDataRef __CFReadSocketsFds
= NULL
;
1068 static CFDataRef zeroLengthData
= NULL
;
1069 static Boolean __CFReadSocketsTimeoutInvalid
= true; /* rebuild the timeout value before calling select */
1071 static CFSocketNativeHandle __CFWakeupSocketPair
[2] = {INVALID_SOCKET
, INVALID_SOCKET
};
1072 static void *__CFSocketManagerThread
= NULL
;
1074 static void __CFSocketDoCallback(CFSocketRef s
, CFDataRef data
, CFDataRef address
, CFSocketNativeHandle sock
);
1077 CFRuntimeBase _base
;
1079 unsigned client
:8; // flags set by client (reenable, CloseOnInvalidate)
1080 unsigned disabled
:8; // flags marking disabled callbacks
1081 unsigned connected
:1; // Are we connected yet? (also true for connectionless sockets)
1082 unsigned writableHint
:1; // Did the polling the socket show it to be writable?
1083 unsigned closeSignaled
:1; // Have we seen FD_CLOSE? (only used on Win32)
1087 CFSpinLock_t _writeLock
;
1088 CFSocketNativeHandle _socket
; /* immutable */
1092 CFDataRef _peerAddress
;
1093 SInt32 _socketSetCount
;
1094 CFRunLoopSourceRef _source0
; // v0 RLS, messaged from SocketMgr
1095 CFMutableArrayRef _runLoops
;
1096 CFSocketCallBack _callout
; /* immutable */
1097 CFSocketContext _context
; /* immutable */
1098 CFMutableArrayRef _dataQueue
; // queues to pass data from SocketMgr thread
1099 CFMutableArrayRef _addressQueue
;
1101 struct timeval _readBufferTimeout
;
1102 CFMutableDataRef _readBuffer
;
1103 CFIndex _bytesToBuffer
; /* is length of _readBuffer */
1104 CFIndex _bytesToBufferPos
; /* where the next _CFSocketRead starts from */
1105 CFIndex _bytesToBufferReadPos
; /* Where the buffer will next be read into (always after _bytesToBufferPos, but less than _bytesToBuffer) */
1107 int _bufferedReadError
;
1109 CFMutableDataRef _leftoverBytes
;
1112 /* Bit 6 in the base reserved bits is used for write-signalled state (mutable) */
1113 /* Bit 5 in the base reserved bits is used for read-signalled state (mutable) */
1114 /* Bit 4 in the base reserved bits is used for invalid state (mutable) */
1115 /* Bits 0-3 in the base reserved bits are used for callback types (immutable) */
1116 /* Of this, bits 0-1 are used for the read callback type. */
1118 CF_INLINE Boolean
__CFSocketIsWriteSignalled(CFSocketRef s
) {
1119 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 6, 6);
1122 CF_INLINE
void __CFSocketSetWriteSignalled(CFSocketRef s
) {
1123 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 6, 6, 1);
1126 CF_INLINE
void __CFSocketUnsetWriteSignalled(CFSocketRef s
) {
1127 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 6, 6, 0);
1130 CF_INLINE Boolean
__CFSocketIsReadSignalled(CFSocketRef s
) {
1131 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 5, 5);
1134 CF_INLINE
void __CFSocketSetReadSignalled(CFSocketRef s
) {
1135 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 5, 5, 1);
1138 CF_INLINE
void __CFSocketUnsetReadSignalled(CFSocketRef s
) {
1139 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 5, 5, 0);
1142 CF_INLINE Boolean
__CFSocketIsValid(CFSocketRef s
) {
1143 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 4, 4);
1146 CF_INLINE
void __CFSocketSetValid(CFSocketRef s
) {
1147 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 4, 4, 1);
1150 CF_INLINE
void __CFSocketUnsetValid(CFSocketRef s
) {
1151 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 4, 4, 0);
1154 CF_INLINE
uint8_t __CFSocketCallBackTypes(CFSocketRef s
) {
1155 return (uint8_t)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 3, 0);
1158 CF_INLINE
uint8_t __CFSocketReadCallBackType(CFSocketRef s
) {
1159 return (uint8_t)__CFBitfieldGetValue(((const CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 1, 0);
1162 CF_INLINE
void __CFSocketSetCallBackTypes(CFSocketRef s
, uint8_t types
) {
1163 __CFBitfieldSetValue(((CFRuntimeBase
*)s
)->_cfinfo
[CF_INFO_BITS
], 3, 0, types
& 0xF);
1166 CF_INLINE
void __CFSocketLock(CFSocketRef s
) {
1167 __CFSpinLock(&(s
->_lock
));
1170 CF_INLINE
void __CFSocketUnlock(CFSocketRef s
) {
1171 __CFSpinUnlock(&(s
->_lock
));
1174 CF_INLINE Boolean
__CFSocketIsConnectionOriented(CFSocketRef s
) {
1175 return (SOCK_STREAM
== s
->_socketType
|| SOCK_SEQPACKET
== s
->_socketType
);
1178 CF_INLINE Boolean
__CFSocketIsScheduled(CFSocketRef s
) {
1179 return (s
->_socketSetCount
> 0);
1182 CF_INLINE
void __CFSocketEstablishAddress(CFSocketRef s
) {
1183 /* socket should already be locked */
1184 uint8_t name
[MAX_SOCKADDR_LEN
];
1185 int namelen
= sizeof(name
);
1186 if (__CFSocketIsValid(s
) && NULL
== s
->_address
&& INVALID_SOCKET
!= s
->_socket
&& 0 == getsockname(s
->_socket
, (struct sockaddr
*)name
, (socklen_t
*)&namelen
) && NULL
!= name
&& 0 < namelen
) {
1187 s
->_address
= CFDataCreate(CFGetAllocator(s
), name
, namelen
);
1191 CF_INLINE
void __CFSocketEstablishPeerAddress(CFSocketRef s
) {
1192 /* socket should already be locked */
1193 uint8_t name
[MAX_SOCKADDR_LEN
];
1194 int namelen
= sizeof(name
);
1195 if (__CFSocketIsValid(s
) && NULL
== s
->_peerAddress
&& INVALID_SOCKET
!= s
->_socket
&& 0 == getpeername(s
->_socket
, (struct sockaddr
*)name
, (socklen_t
*)&namelen
) && NULL
!= name
&& 0 < namelen
) {
1196 s
->_peerAddress
= CFDataCreate(CFGetAllocator(s
), name
, namelen
);
1200 static Boolean
__CFNativeSocketIsValid(CFSocketNativeHandle sock
) {
1201 #if DEPLOYMENT_TARGET_WINDOWS
1202 SInt32 errorCode
= 0;
1203 int errorSize
= sizeof(errorCode
);
1204 return !(0 != getsockopt(sock
, SOL_SOCKET
, SO_ERROR
, (char *)&errorCode
, &errorSize
) && __CFSocketLastError() == WSAENOTSOCK
);
1206 SInt32 flags
= fcntl(sock
, F_GETFL
, 0);
1207 return !(0 > flags
&& EBADF
== __CFSocketLastError());
1211 CF_INLINE Boolean
__CFSocketFdClr(CFSocketNativeHandle sock
, CFMutableDataRef fdSet
) {
1212 /* returns true if a change occurred, false otherwise */
1213 Boolean retval
= false;
1214 if (INVALID_SOCKET
!= sock
&& 0 <= sock
) {
1215 CFIndex numFds
= NBBY
* CFDataGetLength(fdSet
);
1217 if (sock
< numFds
) {
1218 fds_bits
= (fd_mask
*)CFDataGetMutableBytePtr(fdSet
);
1219 if (FD_ISSET(sock
, (fd_set
*)fds_bits
)) {
1221 FD_CLR(sock
, (fd_set
*)fds_bits
);
1228 static SInt32
__CFSocketCreateWakeupSocketPair(void) {
1229 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1232 error
= socketpair(PF_LOCAL
, SOCK_DGRAM
, 0, __CFWakeupSocketPair
);
1233 if (0 <= error
) error
= fcntl(__CFWakeupSocketPair
[0], F_SETFD
, FD_CLOEXEC
);
1234 if (0 <= error
) error
= fcntl(__CFWakeupSocketPair
[1], F_SETFD
, FD_CLOEXEC
);
1236 closesocket(__CFWakeupSocketPair
[0]);
1237 closesocket(__CFWakeupSocketPair
[1]);
1238 __CFWakeupSocketPair
[0] = INVALID_SOCKET
;
1239 __CFWakeupSocketPair
[1] = INVALID_SOCKET
;
1244 struct sockaddr_in address
[2];
1245 int namelen
= sizeof(struct sockaddr_in
);
1246 for (i
= 0; i
< 2; i
++) {
1247 __CFWakeupSocketPair
[i
] = socket(PF_INET
, SOCK_DGRAM
, 0);
1248 memset(&(address
[i
]), 0, sizeof(struct sockaddr_in
));
1249 address
[i
].sin_family
= AF_INET
;
1250 address
[i
].sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
1251 if (0 <= error
) error
= bind(__CFWakeupSocketPair
[i
], (struct sockaddr
*)&(address
[i
]), sizeof(struct sockaddr_in
));
1252 if (0 <= error
) error
= getsockname(__CFWakeupSocketPair
[i
], (struct sockaddr
*)&(address
[i
]), &namelen
);
1253 if (sizeof(struct sockaddr_in
) != namelen
) error
= -1;
1255 if (0 <= error
) error
= connect(__CFWakeupSocketPair
[0], (struct sockaddr
*)&(address
[1]), sizeof(struct sockaddr_in
));
1256 if (0 <= error
) error
= connect(__CFWakeupSocketPair
[1], (struct sockaddr
*)&(address
[0]), sizeof(struct sockaddr_in
));
1258 closesocket(__CFWakeupSocketPair
[0]);
1259 closesocket(__CFWakeupSocketPair
[1]);
1260 __CFWakeupSocketPair
[0] = INVALID_SOCKET
;
1261 __CFWakeupSocketPair
[1] = INVALID_SOCKET
;
1264 #if defined(LOG_CFSOCKET)
1265 fprintf(stdout
, "wakeup socket pair is %d / %d\n", __CFWakeupSocketPair
[0], __CFWakeupSocketPair
[1]);
1271 // Version 0 RunLoopSources set a mask in an FD set to control what socket activity we hear about.
1272 // Changes to the master fs_sets occur via these 4 functions.
1273 CF_INLINE Boolean
__CFSocketSetFDForRead(CFSocketRef s
) {
1274 __CFReadSocketsTimeoutInvalid
= true;
1275 Boolean b
= __CFSocketFdSet(s
->_socket
, __CFReadSocketsFds
);
1276 if (b
&& INVALID_SOCKET
!= __CFWakeupSocketPair
[0]) {
1278 send(__CFWakeupSocketPair
[0], (const char *)&c
, sizeof(c
), 0);
1283 CF_INLINE Boolean
__CFSocketClearFDForRead(CFSocketRef s
) {
1284 __CFReadSocketsTimeoutInvalid
= true;
1285 Boolean b
= __CFSocketFdClr(s
->_socket
, __CFReadSocketsFds
);
1286 if (b
&& INVALID_SOCKET
!= __CFWakeupSocketPair
[0]) {
1288 send(__CFWakeupSocketPair
[0], (const char *)&c
, sizeof(c
), 0);
1293 CF_INLINE Boolean
__CFSocketSetFDForWrite(CFSocketRef s
) {
1294 // CFLog(5, CFSTR("__CFSocketSetFDForWrite(%p)"), s);
1295 Boolean b
= __CFSocketFdSet(s
->_socket
, __CFWriteSocketsFds
);
1296 if (b
&& INVALID_SOCKET
!= __CFWakeupSocketPair
[0]) {
1298 send(__CFWakeupSocketPair
[0], (const char *)&c
, sizeof(c
), 0);
1303 CF_INLINE Boolean
__CFSocketClearFDForWrite(CFSocketRef s
) {
1304 // CFLog(5, CFSTR("__CFSocketClearFDForWrite(%p)"), s);
1305 Boolean b
= __CFSocketFdClr(s
->_socket
, __CFWriteSocketsFds
);
1306 if (b
&& INVALID_SOCKET
!= __CFWakeupSocketPair
[0]) {
1308 send(__CFWakeupSocketPair
[0], (const char *)&c
, sizeof(c
), 0);
1313 #if DEPLOYMENT_TARGET_WINDOWS
1314 static Boolean WinSockUsed
= FALSE
;
1316 static void __CFSocketInitializeWinSock_Guts(void) {
1319 WORD versionRequested
= MAKEWORD(2, 2);
1321 int errorStatus
= WSAStartup(versionRequested
, &wsaData
);
1322 if (errorStatus
!= 0 || LOBYTE(wsaData
.wVersion
) != LOBYTE(versionRequested
) || HIBYTE(wsaData
.wVersion
) != HIBYTE(versionRequested
)) {
1324 CFLog(kCFLogLevelWarning
, CFSTR("*** Could not initialize WinSock subsystem!!!"));
1329 CF_EXPORT
void __CFSocketInitializeWinSock(void) {
1330 __CFSpinLock(&__CFActiveSocketsLock
);
1331 __CFSocketInitializeWinSock_Guts();
1332 __CFSpinUnlock(&__CFActiveSocketsLock
);
1335 __private_extern__
void __CFSocketCleanup(void) {
1336 if (INVALID_SOCKET
!= __CFWakeupSocketPair
[0]) {
1337 closesocket(__CFWakeupSocketPair
[0]);
1338 __CFWakeupSocketPair
[0] = INVALID_SOCKET
;
1340 if (INVALID_SOCKET
!= __CFWakeupSocketPair
[1]) {
1341 closesocket(__CFWakeupSocketPair
[1]);
1342 __CFWakeupSocketPair
[1] = INVALID_SOCKET
;
1345 // 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
1352 // CFNetwork needs to call this, especially for Win32 to get WSAStartup
1353 static void __CFSocketInitializeSockets(void) {
1354 __CFWriteSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
);
1355 __CFReadSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
);
1356 __CFWriteSocketsFds
= CFDataCreateMutable(kCFAllocatorSystemDefault
, 0);
1357 __CFReadSocketsFds
= CFDataCreateMutable(kCFAllocatorSystemDefault
, 0);
1358 zeroLengthData
= CFDataCreateMutable(kCFAllocatorSystemDefault
, 0);
1359 #if DEPLOYMENT_TARGET_WINDOWS
1360 __CFSocketInitializeWinSock_Guts();
1362 if (0 > __CFSocketCreateWakeupSocketPair()) {
1363 CFLog(kCFLogLevelWarning
, CFSTR("*** Could not create wakeup socket pair for CFSocket!!!"));
1366 /* wakeup sockets must be non-blocking */
1367 ioctlsocket(__CFWakeupSocketPair
[0], FIONBIO
, (u_long
*)&yes
);
1368 ioctlsocket(__CFWakeupSocketPair
[1], FIONBIO
, (u_long
*)&yes
);
1369 __CFSocketFdSet(__CFWakeupSocketPair
[1], __CFReadSocketsFds
);
1373 static CFRunLoopRef
__CFSocketCopyRunLoopToWakeUp(CFRunLoopSourceRef src
, CFMutableArrayRef runLoops
) {
1374 if (!src
) return NULL
;
1375 CFRunLoopRef rl
= NULL
;
1376 SInt32 idx
, cnt
= CFArrayGetCount(runLoops
);
1378 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(runLoops
, 0);
1379 for (idx
= 1; NULL
!= rl
&& idx
< cnt
; idx
++) {
1380 CFRunLoopRef value
= (CFRunLoopRef
)CFArrayGetValueAtIndex(runLoops
, idx
);
1381 if (value
!= rl
) rl
= NULL
;
1383 if (NULL
== rl
) { /* more than one different rl, so we must pick one */
1384 /* ideally, this would be a run loop which isn't also in a
1385 * signaled state for this or another source, but that's tricky;
1386 * we pick one that is running in an appropriate mode for this
1387 * source, and from those if possible one that is waiting; then
1388 * we move this run loop to the end of the list to scramble them
1389 * a bit, and always search from the front */
1390 Boolean foundIt
= false, foundBackup
= false;
1391 SInt32 foundIdx
= 0;
1392 for (idx
= 0; !foundIt
&& idx
< cnt
; idx
++) {
1393 CFRunLoopRef value
= (CFRunLoopRef
)CFArrayGetValueAtIndex(runLoops
, idx
);
1394 CFStringRef currentMode
= CFRunLoopCopyCurrentMode(value
);
1395 if (NULL
!= currentMode
) {
1396 if (CFRunLoopContainsSource(value
, src
, currentMode
)) {
1397 if (CFRunLoopIsWaiting(value
)) {
1400 } else if (!foundBackup
) {
1405 CFRelease(currentMode
);
1408 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(runLoops
, foundIdx
);
1410 CFArrayRemoveValueAtIndex(runLoops
, foundIdx
);
1411 CFArrayAppendValue(runLoops
, rl
);
1419 // If callBackNow, we immediately do client callbacks, else we have to signal a v0 RunLoopSource so the
1420 // callbacks can happen in another thread.
1421 static void __CFSocketHandleWrite(CFSocketRef s
, Boolean callBackNow
) {
1422 SInt32 errorCode
= 0;
1423 int errorSize
= sizeof(errorCode
);
1424 CFOptionFlags writeCallBacksAvailable
;
1426 if (!CFSocketIsValid(s
)) return;
1427 if (0 != (s
->_f
.client
& kCFSocketLeaveErrors
) || 0 != getsockopt(s
->_socket
, SOL_SOCKET
, SO_ERROR
, (char *)&errorCode
, (socklen_t
*)&errorSize
)) errorCode
= 0;
1428 // cast for WinSock bad API
1429 #if defined(LOG_CFSOCKET)
1430 if (errorCode
) fprintf(stdout
, "error %ld on socket %d\n", (long)errorCode
, s
->_socket
);
1433 writeCallBacksAvailable
= __CFSocketCallBackTypes(s
) & (kCFSocketWriteCallBack
| kCFSocketConnectCallBack
);
1434 if ((s
->_f
.client
& kCFSocketConnectCallBack
) != 0) writeCallBacksAvailable
&= ~kCFSocketConnectCallBack
;
1435 if (!__CFSocketIsValid(s
) || ((s
->_f
.disabled
& writeCallBacksAvailable
) == writeCallBacksAvailable
)) {
1436 __CFSocketUnlock(s
);
1439 s
->_errorCode
= errorCode
;
1440 __CFSocketSetWriteSignalled(s
);
1441 // CFLog(5, CFSTR("__CFSocketHandleWrite() signalling write on socket %p"), s);
1442 #if defined(LOG_CFSOCKET)
1443 fprintf(stdout
, "write signaling source for socket %d\n", s
->_socket
);
1446 __CFSocketDoCallback(s
, NULL
, NULL
, 0);
1448 CFRunLoopSourceSignal(s
->_source0
);
1449 CFMutableArrayRef runLoopsOrig
= (CFMutableArrayRef
)CFRetain(s
->_runLoops
);
1450 CFMutableArrayRef runLoopsCopy
= CFArrayCreateMutableCopy(kCFAllocatorSystemDefault
, 0, s
->_runLoops
);
1451 CFRunLoopSourceRef source0
= s
->_source0
;
1452 if (NULL
!= source0
&& !CFRunLoopSourceIsValid(source0
)) {
1455 if (source0
) CFRetain(source0
);
1456 __CFSocketUnlock(s
);
1457 CFRunLoopRef rl
= __CFSocketCopyRunLoopToWakeUp(source0
, runLoopsCopy
);
1458 if (source0
) CFRelease(source0
);
1460 CFRunLoopWakeUp(rl
);
1464 if (runLoopsOrig
== s
->_runLoops
) {
1465 s
->_runLoops
= runLoopsCopy
;
1466 runLoopsCopy
= NULL
;
1467 CFRelease(runLoopsOrig
);
1469 __CFSocketUnlock(s
);
1470 CFRelease(runLoopsOrig
);
1471 if (runLoopsCopy
) CFRelease(runLoopsCopy
);
1475 static void __CFSocketHandleRead(CFSocketRef s
, Boolean causedByTimeout
)
1477 CFDataRef data
= NULL
, address
= NULL
;
1478 CFSocketNativeHandle sock
= INVALID_SOCKET
;
1479 if (!CFSocketIsValid(s
)) return;
1480 if (__CFSocketReadCallBackType(s
) == kCFSocketDataCallBack
) {
1481 uint8_t bufferArray
[MAX_CONNECTION_ORIENTED_DATA_SIZE
], *buffer
;
1482 uint8_t name
[MAX_SOCKADDR_LEN
];
1483 int namelen
= sizeof(name
);
1485 if (__CFSocketIsConnectionOriented(s
)) {
1486 buffer
= bufferArray
;
1487 recvlen
= recvfrom(s
->_socket
, (char *)buffer
, MAX_CONNECTION_ORIENTED_DATA_SIZE
, 0, (struct sockaddr
*)name
, (socklen_t
*)&namelen
);
1489 buffer
= (uint8_t *)malloc(MAX_DATA_SIZE
);
1490 if (buffer
) recvlen
= recvfrom(s
->_socket
, (char *)buffer
, MAX_DATA_SIZE
, 0, (struct sockaddr
*)name
, (socklen_t
*)&namelen
);
1492 #if defined(LOG_CFSOCKET)
1493 fprintf(stdout
, "read %ld bytes on socket %d\n", (long)recvlen
, s
->_socket
);
1496 //??? should return error if <0
1497 /* zero-length data is the signal for perform to invalidate */
1498 data
= (CFDataRef
)CFRetain(zeroLengthData
);
1500 data
= CFDataCreate(CFGetAllocator(s
), buffer
, recvlen
);
1502 if (buffer
&& buffer
!= bufferArray
) free(buffer
);
1504 if (!__CFSocketIsValid(s
)) {
1506 __CFSocketUnlock(s
);
1509 __CFSocketSetReadSignalled(s
);
1510 if (NULL
!= name
&& 0 < namelen
) {
1511 //??? possible optimizations: uniquing; storing last value
1512 address
= CFDataCreate(CFGetAllocator(s
), name
, namelen
);
1513 } else if (__CFSocketIsConnectionOriented(s
)) {
1514 if (NULL
== s
->_peerAddress
) __CFSocketEstablishPeerAddress(s
);
1515 if (NULL
!= s
->_peerAddress
) address
= (CFDataRef
)CFRetain(s
->_peerAddress
);
1517 if (NULL
== address
) {
1518 address
= (CFDataRef
)CFRetain(zeroLengthData
);
1520 if (NULL
== s
->_dataQueue
) {
1521 s
->_dataQueue
= CFArrayCreateMutable(CFGetAllocator(s
), 0, &kCFTypeArrayCallBacks
);
1523 if (NULL
== s
->_addressQueue
) {
1524 s
->_addressQueue
= CFArrayCreateMutable(CFGetAllocator(s
), 0, &kCFTypeArrayCallBacks
);
1526 CFArrayAppendValue(s
->_dataQueue
, data
);
1528 CFArrayAppendValue(s
->_addressQueue
, address
);
1531 && (s
->_f
.client
& kCFSocketDataCallBack
) != 0 && (s
->_f
.disabled
& kCFSocketDataCallBack
) == 0
1532 && __CFSocketIsScheduled(s
)
1534 __CFSpinLock(&__CFActiveSocketsLock
);
1535 /* restore socket to fds */
1536 __CFSocketSetFDForRead(s
);
1537 __CFSpinUnlock(&__CFActiveSocketsLock
);
1539 } else if (__CFSocketReadCallBackType(s
) == kCFSocketAcceptCallBack
) {
1540 uint8_t name
[MAX_SOCKADDR_LEN
];
1541 int namelen
= sizeof(name
);
1542 sock
= accept(s
->_socket
, (struct sockaddr
*)name
, (socklen_t
*)&namelen
);
1543 if (INVALID_SOCKET
== sock
) {
1544 //??? should return error
1547 if (NULL
!= name
&& 0 < namelen
) {
1548 address
= CFDataCreate(CFGetAllocator(s
), name
, namelen
);
1550 address
= (CFDataRef
)CFRetain(zeroLengthData
);
1553 if (!__CFSocketIsValid(s
)) {
1556 __CFSocketUnlock(s
);
1559 __CFSocketSetReadSignalled(s
);
1560 if (NULL
== s
->_dataQueue
) {
1561 s
->_dataQueue
= CFArrayCreateMutable(CFGetAllocator(s
), 0, NULL
);
1563 if (NULL
== s
->_addressQueue
) {
1564 s
->_addressQueue
= CFArrayCreateMutable(CFGetAllocator(s
), 0, &kCFTypeArrayCallBacks
);
1566 CFArrayAppendValue(s
->_dataQueue
, (void *)(uintptr_t)sock
);
1567 CFArrayAppendValue(s
->_addressQueue
, address
);
1569 if ((s
->_f
.client
& kCFSocketAcceptCallBack
) != 0 && (s
->_f
.disabled
& kCFSocketAcceptCallBack
) == 0
1570 && __CFSocketIsScheduled(s
)
1572 __CFSpinLock(&__CFActiveSocketsLock
);
1573 /* restore socket to fds */
1574 __CFSocketSetFDForRead(s
);
1575 __CFSpinUnlock(&__CFActiveSocketsLock
);
1579 if (!__CFSocketIsValid(s
) || (s
->_f
.disabled
& kCFSocketReadCallBack
) != 0) {
1580 __CFSocketUnlock(s
);
1584 if (causedByTimeout
) {
1585 #if defined(LOG_CFSOCKET)
1586 fprintf(stdout
, "TIMEOUT RECEIVED - WILL SIGNAL IMMEDIATELY TO FLUSH (%ld buffered)\n", s
->_bytesToBufferPos
);
1588 /* we've got a timeout, but no bytes read. Ignore the timeout. */
1589 if (s
->_bytesToBufferPos
== 0) {
1590 #if defined(LOG_CFSOCKET)
1591 fprintf(stdout
, "TIMEOUT - but no bytes, restoring to active set\n");
1595 __CFSpinLock(&__CFActiveSocketsLock
);
1596 /* restore socket to fds */
1597 __CFSocketSetFDForRead(s
);
1598 __CFSpinUnlock(&__CFActiveSocketsLock
);
1599 __CFSocketUnlock(s
);
1602 } else if (s
->_bytesToBuffer
!= 0 && ! s
->_atEOF
) {
1605 CFIndex ctRemaining
= s
->_bytesToBuffer
- s
->_bytesToBufferPos
;
1607 /* if our buffer has room, we go ahead and buffer */
1608 if (ctRemaining
> 0) {
1609 base
= CFDataGetMutableBytePtr(s
->_readBuffer
);
1612 ctRead
= read(CFSocketGetNative(s
), &base
[s
->_bytesToBufferPos
], ctRemaining
);
1613 } while (ctRead
== -1 && errno
== EAGAIN
);
1617 s
->_bufferedReadError
= errno
;
1619 #if defined(LOG_CFSOCKET)
1620 fprintf(stderr
, "BUFFERED READ GOT ERROR %d\n", errno
);
1625 #if defined(LOG_CFSOCKET)
1626 fprintf(stdout
, "DONE READING (EOF) - GOING TO SIGNAL\n");
1632 s
->_bytesToBufferPos
+= ctRead
;
1633 if (s
->_bytesToBuffer
!= s
->_bytesToBufferPos
) {
1634 #if defined(LOG_CFSOCKET)
1635 fprintf(stdout
, "READ %ld - need %ld MORE - GOING BACK FOR MORE\n", ctRead
, s
->_bytesToBuffer
- s
->_bytesToBufferPos
);
1637 __CFSpinLock(&__CFActiveSocketsLock
);
1638 /* restore socket to fds */
1639 __CFSocketSetFDForRead(s
);
1640 __CFSpinUnlock(&__CFActiveSocketsLock
);
1641 __CFSocketUnlock(s
);
1644 #if defined(LOG_CFSOCKET)
1645 fprintf(stdout
, "DONE READING (read %ld bytes) - GOING TO SIGNAL\n", ctRead
);
1652 __CFSocketSetReadSignalled(s
);
1654 #if defined(LOG_CFSOCKET)
1655 fprintf(stdout
, "read signaling source for socket %d\n", s
->_socket
);
1657 CFRunLoopSourceSignal(s
->_source0
);
1658 CFMutableArrayRef runLoopsOrig
= (CFMutableArrayRef
)CFRetain(s
->_runLoops
);
1659 CFMutableArrayRef runLoopsCopy
= CFArrayCreateMutableCopy(kCFAllocatorSystemDefault
, 0, s
->_runLoops
);
1660 CFRunLoopSourceRef source0
= s
->_source0
;
1661 if (NULL
!= source0
&& !CFRunLoopSourceIsValid(source0
)) {
1664 if (source0
) CFRetain(source0
);
1665 __CFSocketUnlock(s
);
1666 CFRunLoopRef rl
= __CFSocketCopyRunLoopToWakeUp(source0
, runLoopsCopy
);
1667 if (source0
) CFRelease(source0
);
1669 CFRunLoopWakeUp(rl
);
1673 if (runLoopsOrig
== s
->_runLoops
) {
1674 s
->_runLoops
= runLoopsCopy
;
1675 runLoopsCopy
= NULL
;
1676 CFRelease(runLoopsOrig
);
1678 __CFSocketUnlock(s
);
1679 CFRelease(runLoopsOrig
);
1680 if (runLoopsCopy
) CFRelease(runLoopsCopy
);
1683 static struct timeval
* intervalToTimeval(CFTimeInterval timeout
, struct timeval
* tv
)
1688 tv
->tv_sec
= (0 >= timeout
|| INT_MAX
<= timeout
) ? INT_MAX
: (int)(float)floor(timeout
);
1689 tv
->tv_usec
= (int)((timeout
- floor(timeout
)) * 1.0E6
);
1694 /* note that this returns a pointer to the min value, which won't have changed during
1695 the dictionary apply, since we've got the active sockets lock held */
1696 static void _calcMinTimeout_locked(const void* val
, void* ctxt
)
1698 CFSocketRef s
= (CFSocketRef
) val
;
1699 struct timeval
** minTime
= (struct timeval
**) ctxt
;
1700 if (timerisset(&s
->_readBufferTimeout
) && (*minTime
== NULL
|| timercmp(&s
->_readBufferTimeout
, *minTime
, <)))
1701 *minTime
= &s
->_readBufferTimeout
;
1702 else if (s
->_leftoverBytes
) {
1703 /* If there's anyone with leftover bytes, they'll need to be awoken immediately */
1704 static struct timeval sKickerTime
= { 0, 0 };
1705 *minTime
= &sKickerTime
;
1709 void __CFSocketSetSocketReadBufferAttrs(CFSocketRef s
, CFTimeInterval timeout
, CFIndex length
)
1711 struct timeval timeoutVal
;
1713 intervalToTimeval(timeout
, &timeoutVal
);
1715 /* lock ordering is socket lock, activesocketslock */
1716 /* activesocketslock protects our timeout calculation */
1718 __CFSpinLock(&__CFActiveSocketsLock
);
1720 if (s
->_bytesToBuffer
!= length
) {
1721 CFIndex ctBuffer
= s
->_bytesToBufferPos
- s
->_bytesToBufferReadPos
;
1724 /* As originally envisaged, you were supposed to be sure to drain the buffer before
1725 * issuing another request on the socket. In practice, there seem to be times when we want to re-use
1726 * the stream (or perhaps, are on our way to closing it out) and this policy doesn't work so well.
1727 * So, if someone changes the buffer size while we have bytes already buffered, we put them
1728 * aside and use them to satisfy any subsequent reads.
1730 #if defined(LOG_CFSOCKET)
1731 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);
1734 if (s
->_leftoverBytes
== NULL
)
1735 s
->_leftoverBytes
= CFDataCreateMutable(CFGetAllocator(s
), 0);
1737 /* append the current buffered bytes over. We'll keep draining _leftoverBytes while we have them... */
1738 CFDataAppendBytes(s
->_leftoverBytes
, CFDataGetBytePtr(s
->_readBuffer
) + s
->_bytesToBufferReadPos
, ctBuffer
);
1739 CFRelease(s
->_readBuffer
);
1740 s
->_readBuffer
= NULL
;
1742 s
->_bytesToBuffer
= 0;
1743 s
->_bytesToBufferPos
= 0;
1744 s
->_bytesToBufferReadPos
= 0;
1747 s
->_bytesToBuffer
= 0;
1748 s
->_bytesToBufferPos
= 0;
1749 s
->_bytesToBufferReadPos
= 0;
1750 if (s
->_readBuffer
) {
1751 CFRelease(s
->_readBuffer
);
1752 s
->_readBuffer
= NULL
;
1754 // Zero length buffer, smash the timeout
1755 timeoutVal
.tv_sec
= 0;
1756 timeoutVal
.tv_usec
= 0;
1758 /* if the buffer shrank, we can re-use the old one */
1759 if (length
> s
->_bytesToBuffer
) {
1760 if (s
->_readBuffer
) {
1761 CFRelease(s
->_readBuffer
);
1762 s
->_readBuffer
= NULL
;
1766 s
->_bytesToBuffer
= length
;
1767 s
->_bytesToBufferPos
= 0;
1768 s
->_bytesToBufferReadPos
= 0;
1769 if (s
->_readBuffer
== NULL
) {
1770 s
->_readBuffer
= CFDataCreateMutable(kCFAllocatorSystemDefault
, length
);
1771 CFDataSetLength(s
->_readBuffer
, length
);
1776 if (timercmp(&s
->_readBufferTimeout
, &timeoutVal
, !=)) {
1777 s
->_readBufferTimeout
= timeoutVal
;
1778 __CFReadSocketsTimeoutInvalid
= true;
1781 __CFSpinUnlock(&__CFActiveSocketsLock
);
1782 __CFSocketUnlock(s
);
1785 CFIndex
__CFSocketRead(CFSocketRef s
, UInt8
* buffer
, CFIndex length
, int* error
)
1787 #if defined(LOG_CFSOCKET)
1788 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
);
1791 CFIndex result
= -1;
1797 /* Any leftover buffered bytes? */
1798 if (s
->_leftoverBytes
) {
1799 CFIndex ctBuffer
= CFDataGetLength(s
->_leftoverBytes
);
1801 fprintf(stderr
, "%s(%ld): WARNING: Draining %ld leftover bytes first\n\n", __FUNCTION__
, (long)__LINE__
, (long)ctBuffer
);
1803 if (ctBuffer
> length
)
1805 memcpy(buffer
, CFDataGetBytePtr(s
->_leftoverBytes
), ctBuffer
);
1806 if (ctBuffer
< CFDataGetLength(s
->_leftoverBytes
))
1807 CFDataReplaceBytes(s
->_leftoverBytes
, CFRangeMake(0, ctBuffer
), NULL
, 0);
1809 CFRelease(s
->_leftoverBytes
);
1810 s
->_leftoverBytes
= NULL
;
1816 /* return whatever we've buffered */
1817 if (s
->_bytesToBuffer
!= 0) {
1818 CFIndex ctBuffer
= s
->_bytesToBufferPos
- s
->_bytesToBufferReadPos
;
1820 /* drain our buffer first */
1821 if (ctBuffer
> length
)
1823 memcpy(buffer
, CFDataGetBytePtr(s
->_readBuffer
) + s
->_bytesToBufferReadPos
, ctBuffer
);
1824 s
->_bytesToBufferReadPos
+= ctBuffer
;
1825 if (s
->_bytesToBufferReadPos
== s
->_bytesToBufferPos
) {
1826 #if defined(LOG_CFSOCKET)
1827 fprintf(stdout
, "DRAINED BUFFER - SHOULD START BUFFERING AGAIN!\n");
1829 s
->_bytesToBufferPos
= 0;
1830 s
->_bytesToBufferReadPos
= 0;
1833 #if defined(LOG_CFSOCKET)
1834 fprintf(stdout
, "SLURPED %ld BYTES FROM BUFFER %ld LEFT TO READ!\n", ctBuffer
, length
);
1841 /* nothing buffered, or no buffer selected */
1843 /* Did we get an error on a previous read (or buffered read)? */
1844 if (s
->_bufferedReadError
!= 0) {
1845 #if defined(LOG_CFSOCKET)
1846 fprintf(stdout
, "RETURNING ERROR %d\n", s
->_bufferedReadError
);
1848 *error
= s
->_bufferedReadError
;
1853 /* nothing buffered, if we've hit eof, don't bother reading any more */
1855 #if defined(LOG_CFSOCKET)
1856 fprintf(stdout
, "RETURNING EOF\n");
1863 result
= read(CFSocketGetNative(s
), buffer
, length
);
1864 #if defined(LOG_CFSOCKET)
1865 fprintf(stdout
, "READ %ld bytes", result
);
1869 /* note that we hit EOF */
1871 } else if (result
< 0) {
1874 /* if it wasn't EAGAIN, record it (although we shouldn't get called again) */
1875 if (*error
!= EAGAIN
) {
1876 s
->_bufferedReadError
= *error
;
1881 __CFSocketUnlock(s
);
1886 Boolean
__CFSocketGetBytesAvailable(CFSocketRef s
, CFIndex
* ctBytesAvailable
)
1888 CFIndex ctBuffer
= s
->_bytesToBufferPos
- s
->_bytesToBufferReadPos
;
1889 if (ctBuffer
!= 0) {
1890 *ctBytesAvailable
= ctBuffer
;
1894 unsigned long bytesAvailable
;
1895 result
= ioctlsocket(CFSocketGetNative(s
), FIONREAD
, &bytesAvailable
);
1898 *ctBytesAvailable
= (CFIndex
) bytesAvailable
;
1903 #if defined(LOG_CFSOCKET)
1904 static void __CFSocketWriteSocketList(CFArrayRef sockets
, CFDataRef fdSet
, Boolean onlyIfSet
) {
1905 fd_set
*tempfds
= (fd_set
*)CFDataGetBytePtr(fdSet
);
1907 for (idx
= 0, cnt
= CFArrayGetCount(sockets
); idx
< cnt
; idx
++) {
1908 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(sockets
, idx
);
1909 if (FD_ISSET(s
->_socket
, tempfds
)) {
1910 fprintf(stdout
, "%d ", s
->_socket
);
1911 } else if (!onlyIfSet
) {
1912 fprintf(stdout
, "(%d) ", s
->_socket
);
1919 __attribute__ ((noreturn
)) // mostly interesting for shutting up a warning
1920 #endif /* __GNUC__ */
1921 static void __CFSocketManager(void * arg
)
1923 pthread_setname_np("com.apple.CFSocket.private");
1924 if (objc_collectingEnabled()) objc_registerThreadWithCollector();
1925 SInt32 nrfds
, maxnrfds
, fdentries
= 1;
1927 fd_set
*exceptfds
= NULL
;
1928 fd_set
*writefds
= (fd_set
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, fdentries
* sizeof(fd_mask
), 0);
1929 fd_set
*readfds
= (fd_set
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, fdentries
* sizeof(fd_mask
), 0);
1932 uint8_t buffer
[256];
1933 CFMutableArrayRef selectedWriteSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
1934 CFMutableArrayRef selectedReadSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
1935 CFIndex selectedWriteSocketsIndex
= 0, selectedReadSocketsIndex
= 0;
1938 struct timeval
* pTimeout
= NULL
;
1939 struct timeval timeBeforeSelect
;
1942 __CFSpinLock(&__CFActiveSocketsLock
);
1943 __CFSocketManagerIteration
++;
1944 #if defined(LOG_CFSOCKET)
1945 fprintf(stdout
, "socket manager iteration %lu looking at read sockets ", (unsigned long)__CFSocketManagerIteration
);
1946 __CFSocketWriteSocketList(__CFReadSockets
, __CFReadSocketsFds
, FALSE
);
1947 if (0 < CFArrayGetCount(__CFWriteSockets
)) {
1948 fprintf(stdout
, " and write sockets ");
1949 __CFSocketWriteSocketList(__CFWriteSockets
, __CFWriteSocketsFds
, FALSE
);
1951 fprintf(stdout
, "\n");
1953 rfds
= __CFSocketFdGetSize(__CFReadSocketsFds
);
1954 wfds
= __CFSocketFdGetSize(__CFWriteSocketsFds
);
1955 maxnrfds
= __CFMax(rfds
, wfds
);
1956 if (maxnrfds
> fdentries
* (int)NFDBITS
) {
1957 fdentries
= (maxnrfds
+ NFDBITS
- 1) / NFDBITS
;
1958 writefds
= (fd_set
*)CFAllocatorReallocate(kCFAllocatorSystemDefault
, writefds
, fdentries
* sizeof(fd_mask
), 0);
1959 readfds
= (fd_set
*)CFAllocatorReallocate(kCFAllocatorSystemDefault
, readfds
, fdentries
* sizeof(fd_mask
), 0);
1961 memset(writefds
, 0, fdentries
* sizeof(fd_mask
));
1962 memset(readfds
, 0, fdentries
* sizeof(fd_mask
));
1963 CFDataGetBytes(__CFWriteSocketsFds
, CFRangeMake(0, CFDataGetLength(__CFWriteSocketsFds
)), (UInt8
*)writefds
);
1964 CFDataGetBytes(__CFReadSocketsFds
, CFRangeMake(0, CFDataGetLength(__CFReadSocketsFds
)), (UInt8
*)readfds
);
1966 if (__CFReadSocketsTimeoutInvalid
) {
1967 struct timeval
* minTimeout
= NULL
;
1968 __CFReadSocketsTimeoutInvalid
= false;
1969 #if defined(LOG_CFSOCKET)
1970 fprintf(stdout
, "Figuring out which sockets have timeouts...\n");
1972 CFArrayApplyFunction(__CFReadSockets
, CFRangeMake(0, CFArrayGetCount(__CFReadSockets
)), _calcMinTimeout_locked
, (void*) &minTimeout
);
1974 if (minTimeout
== NULL
) {
1975 #if defined(LOG_CFSOCKET)
1976 fprintf(stdout
, "No one wants a timeout!\n");
1980 #if defined(LOG_CFSOCKET)
1981 fprintf(stdout
, "timeout will be %ld, %d!\n", minTimeout
->tv_sec
, minTimeout
->tv_usec
);
1989 #if defined(LOG_CFSOCKET)
1990 fprintf(stdout
, "select will have a %ld, %d timeout\n", pTimeout
->tv_sec
, pTimeout
->tv_usec
);
1992 gettimeofday(&timeBeforeSelect
, NULL
);
1995 __CFSpinUnlock(&__CFActiveSocketsLock
);
1997 #if DEPLOYMENT_TARGET_WINDOWS
1998 // On Windows, select checks connection failed sockets via the exceptfds parameter. connection succeeded is checked via writefds. We need both.
1999 exceptfds
= writefds
;
2001 nrfds
= select(maxnrfds
, readfds
, writefds
, exceptfds
, pTimeout
);
2003 #if defined(LOG_CFSOCKET)
2004 fprintf(stdout
, "socket manager woke from select, ret=%ld\n", (long)nrfds
);
2008 * select returned a timeout
2011 struct timeval timeAfterSelect
;
2012 struct timeval deltaTime
;
2013 gettimeofday(&timeAfterSelect
, NULL
);
2014 /* timeBeforeSelect becomes the delta */
2015 timersub(&timeAfterSelect
, &timeBeforeSelect
, &deltaTime
);
2017 #if defined(LOG_CFSOCKET)
2018 fprintf(stdout
, "Socket manager received timeout - kicking off expired reads (expired delta %ld, %d)\n", deltaTime
.tv_sec
, deltaTime
.tv_usec
);
2021 __CFSpinLock(&__CFActiveSocketsLock
);
2024 cnt
= CFArrayGetCount(__CFReadSockets
);
2025 for (idx
= 0; idx
< cnt
; idx
++) {
2026 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFReadSockets
, idx
);
2027 if (timerisset(&s
->_readBufferTimeout
) || s
->_leftoverBytes
) {
2028 CFSocketNativeHandle sock
= s
->_socket
;
2029 // We might have an new element in __CFReadSockets that we weren't listening to,
2030 // in which case we must be sure not to test a bit in the fdset that is
2031 // outside our mask size.
2032 Boolean sockInBounds
= (0 <= sock
&& sock
< maxnrfds
);
2033 /* if this sockets timeout is less than or equal elapsed time, then signal it */
2034 if (INVALID_SOCKET
!= sock
&& sockInBounds
) {
2035 #if defined(LOG_CFSOCKET)
2036 fprintf(stdout
, "Expiring socket %d (delta %ld, %d)\n", sock
, s
->_readBufferTimeout
.tv_sec
, s
->_readBufferTimeout
.tv_usec
);
2038 CFArraySetValueAtIndex(selectedReadSockets
, selectedReadSocketsIndex
, s
);
2039 selectedReadSocketsIndex
++;
2040 /* socket is removed from fds here, will be restored in read handling or in perform function */
2041 if (!tempfds
) tempfds
= (fd_set
*)CFDataGetMutableBytePtr(__CFReadSocketsFds
);
2042 FD_CLR(sock
, tempfds
);
2047 __CFSpinUnlock(&__CFActiveSocketsLock
);
2049 /* and below, we dispatch through the normal read dispatch mechanism */
2053 SInt32 selectError
= __CFSocketLastError();
2054 #if defined(LOG_CFSOCKET)
2055 fprintf(stdout
, "socket manager received error %ld from select\n", (long)selectError
);
2057 if (EBADF
== selectError
) {
2058 CFMutableArrayRef invalidSockets
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
2059 __CFSpinLock(&__CFActiveSocketsLock
);
2060 cnt
= CFArrayGetCount(__CFWriteSockets
);
2061 for (idx
= 0; idx
< cnt
; idx
++) {
2062 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFWriteSockets
, idx
);
2063 if (!__CFNativeSocketIsValid(s
->_socket
)) {
2064 #if defined(LOG_CFSOCKET)
2065 fprintf(stdout
, "socket manager found write socket %d invalid\n", s
->_socket
);
2067 CFArrayAppendValue(invalidSockets
, s
);
2070 cnt
= CFArrayGetCount(__CFReadSockets
);
2071 for (idx
= 0; idx
< cnt
; idx
++) {
2072 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFReadSockets
, idx
);
2073 if (!__CFNativeSocketIsValid(s
->_socket
)) {
2074 #if defined(LOG_CFSOCKET)
2075 fprintf(stdout
, "socket manager found read socket %d invalid\n", s
->_socket
);
2077 CFArrayAppendValue(invalidSockets
, s
);
2080 __CFSpinUnlock(&__CFActiveSocketsLock
);
2082 cnt
= CFArrayGetCount(invalidSockets
);
2083 for (idx
= 0; idx
< cnt
; idx
++) {
2084 CFSocketInvalidate(((CFSocketRef
)CFArrayGetValueAtIndex(invalidSockets
, idx
)));
2086 CFRelease(invalidSockets
);
2090 if (FD_ISSET(__CFWakeupSocketPair
[1], readfds
)) {
2091 recv(__CFWakeupSocketPair
[1], (char *)buffer
, sizeof(buffer
), 0);
2092 #if defined(LOG_CFSOCKET)
2093 fprintf(stdout
, "socket manager received %c on wakeup socket\n", buffer
[0]);
2096 __CFSpinLock(&__CFActiveSocketsLock
);
2098 cnt
= CFArrayGetCount(__CFWriteSockets
);
2099 for (idx
= 0; idx
< cnt
; idx
++) {
2100 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFWriteSockets
, idx
);
2101 CFSocketNativeHandle sock
= s
->_socket
;
2102 // We might have an new element in __CFWriteSockets that we weren't listening to,
2103 // in which case we must be sure not to test a bit in the fdset that is
2104 // outside our mask size.
2105 Boolean sockInBounds
= (0 <= sock
&& sock
< maxnrfds
);
2106 if (INVALID_SOCKET
!= sock
&& sockInBounds
) {
2107 if (FD_ISSET(sock
, writefds
)) {
2108 CFArraySetValueAtIndex(selectedWriteSockets
, selectedWriteSocketsIndex
, s
);
2109 selectedWriteSocketsIndex
++;
2110 /* socket is removed from fds here, restored by CFSocketReschedule */
2111 if (!tempfds
) tempfds
= (fd_set
*)CFDataGetMutableBytePtr(__CFWriteSocketsFds
);
2112 FD_CLR(sock
, tempfds
);
2113 // CFLog(5, CFSTR("Manager: cleared socket %p from write fds"), s);
2118 cnt
= CFArrayGetCount(__CFReadSockets
);
2119 for (idx
= 0; idx
< cnt
; idx
++) {
2120 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(__CFReadSockets
, idx
);
2121 CFSocketNativeHandle sock
= s
->_socket
;
2122 // We might have an new element in __CFReadSockets that we weren't listening to,
2123 // in which case we must be sure not to test a bit in the fdset that is
2124 // outside our mask size.
2125 Boolean sockInBounds
= (0 <= sock
&& sock
< maxnrfds
);
2126 if (INVALID_SOCKET
!= sock
&& sockInBounds
&& FD_ISSET(sock
, readfds
)) {
2127 CFArraySetValueAtIndex(selectedReadSockets
, selectedReadSocketsIndex
, s
);
2128 selectedReadSocketsIndex
++;
2129 /* socket is removed from fds here, will be restored in read handling or in perform function */
2130 if (!tempfds
) tempfds
= (fd_set
*)CFDataGetMutableBytePtr(__CFReadSocketsFds
);
2131 FD_CLR(sock
, tempfds
);
2134 __CFSpinUnlock(&__CFActiveSocketsLock
);
2136 for (idx
= 0; idx
< selectedWriteSocketsIndex
; idx
++) {
2137 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(selectedWriteSockets
, idx
);
2138 if (kCFNull
== (CFNullRef
)s
) continue;
2139 #if defined(LOG_CFSOCKET)
2140 fprintf(stdout
, "socket manager signaling socket %d for write\n", s
->_socket
);
2142 __CFSocketHandleWrite(s
, FALSE
);
2143 CFArraySetValueAtIndex(selectedWriteSockets
, idx
, kCFNull
);
2145 selectedWriteSocketsIndex
= 0;
2147 for (idx
= 0; idx
< selectedReadSocketsIndex
; idx
++) {
2148 CFSocketRef s
= (CFSocketRef
)CFArrayGetValueAtIndex(selectedReadSockets
, idx
);
2149 if (kCFNull
== (CFNullRef
)s
) continue;
2150 #if defined(LOG_CFSOCKET)
2151 fprintf(stdout
, "socket manager signaling socket %d for read\n", s
->_socket
);
2153 __CFSocketHandleRead(s
, nrfds
== 0);
2154 CFArraySetValueAtIndex(selectedReadSockets
, idx
, kCFNull
);
2156 selectedReadSocketsIndex
= 0;
2160 static CFStringRef
__CFSocketCopyDescription(CFTypeRef cf
) {
2161 CFSocketRef s
= (CFSocketRef
)cf
;
2162 CFMutableStringRef result
;
2163 CFStringRef contextDesc
= NULL
;
2164 void *contextInfo
= NULL
;
2165 CFStringRef (*contextCopyDescription
)(const void *info
) = NULL
;
2166 result
= CFStringCreateMutable(CFGetAllocator(s
), 0);
2168 void *addr
= s
->_callout
;
2169 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2171 const char *name
= (dladdr(addr
, &info
) && info
.dli_saddr
== addr
&& info
.dli_sname
) ? info
.dli_sname
: "???";
2173 // don't bother trying to figure out callout names
2174 const char *name
= "<unknown>";
2176 CFStringAppendFormat(result
, NULL
, CFSTR("<CFSocket %p [%p]>{valid = %s, type = %d, socket = %d, socket set count = %ld,\n callback types = 0x%x, callout = %s (%p), source = %p,\n run loops = %@,\n context = "), cf
, CFGetAllocator(s
), (__CFSocketIsValid(s
) ? "Yes" : "No"), s
->_socketType
, s
->_socket
, s
->_socketSetCount
, __CFSocketCallBackTypes(s
), name
, addr
, s
->_source0
, s
->_runLoops
);
2177 contextInfo
= s
->_context
.info
;
2178 contextCopyDescription
= s
->_context
.copyDescription
;
2179 __CFSocketUnlock(s
);
2180 if (NULL
!= contextInfo
&& NULL
!= contextCopyDescription
) {
2181 contextDesc
= (CFStringRef
)contextCopyDescription(contextInfo
);
2183 if (NULL
== contextDesc
) {
2184 contextDesc
= CFStringCreateWithFormat(CFGetAllocator(s
), NULL
, CFSTR("<CFSocket context %p>"), contextInfo
);
2186 CFStringAppend(result
, contextDesc
);
2187 CFStringAppend(result
, CFSTR("}"));
2188 CFRelease(contextDesc
);
2192 static void __CFSocketDeallocate(CFTypeRef cf
) {
2193 /* Since CFSockets are cached, we can only get here sometime after being invalidated */
2194 CFSocketRef s
= (CFSocketRef
)cf
;
2195 if (NULL
!= s
->_address
) {
2196 CFRelease(s
->_address
);
2199 if (NULL
!= s
->_readBuffer
) {
2200 CFRelease(s
->_readBuffer
);
2201 s
->_readBuffer
= NULL
;
2203 if (NULL
!= s
->_leftoverBytes
) {
2204 CFRelease(s
->_leftoverBytes
);
2205 s
->_leftoverBytes
= NULL
;
2207 timerclear(&s
->_readBufferTimeout
);
2208 s
->_bytesToBuffer
= 0;
2209 s
->_bytesToBufferPos
= 0;
2210 s
->_bytesToBufferReadPos
= 0;
2212 s
->_bufferedReadError
= 0;
2215 static CFTypeID __kCFSocketTypeID
= _kCFRuntimeNotATypeID
;
2217 static const CFRuntimeClass __CFSocketClass
= {
2222 __CFSocketDeallocate
,
2226 __CFSocketCopyDescription
2229 CFTypeID
CFSocketGetTypeID(void) {
2230 if (_kCFRuntimeNotATypeID
== __kCFSocketTypeID
) {
2231 __kCFSocketTypeID
= _CFRuntimeRegisterClass(&__CFSocketClass
);
2232 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2234 int ret1
= getrlimit(RLIMIT_NOFILE
, &lim1
);
2235 int mib
[] = {CTL_KERN
, KERN_MAXFILESPERPROC
};
2237 size_t len
= sizeof(int);
2238 int ret0
= sysctl(mib
, 2, &maxfd
, &len
, NULL
, 0);
2239 if (0 == ret0
&& 0 == ret1
&& lim1
.rlim_max
< maxfd
) maxfd
= lim1
.rlim_max
;
2240 if (0 == ret1
&& lim1
.rlim_cur
< maxfd
) {
2241 struct rlimit lim2
= lim1
;
2242 lim2
.rlim_cur
+= 2304;
2243 if (maxfd
< lim2
.rlim_cur
) lim2
.rlim_cur
= maxfd
;
2244 setrlimit(RLIMIT_NOFILE
, &lim2
);
2245 // we try, but do not go to extraordinary measures
2249 return __kCFSocketTypeID
;
2252 static CFSocketRef
_CFSocketCreateWithNative(CFAllocatorRef allocator
, CFSocketNativeHandle sock
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
, Boolean useExistingInstance
) {
2255 int typeSize
= sizeof(memory
->_socketType
);
2256 __CFSpinLock(&__CFActiveSocketsLock
);
2257 if (NULL
== __CFReadSockets
) __CFSocketInitializeSockets();
2258 __CFSpinUnlock(&__CFActiveSocketsLock
);
2259 __CFSpinLock(&__CFAllSocketsLock
);
2260 if (NULL
== __CFAllSockets
) {
2261 __CFAllSockets
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, &kCFTypeDictionaryValueCallBacks
);
2263 if (INVALID_SOCKET
!= sock
&& CFDictionaryGetValueIfPresent(__CFAllSockets
, (void *)(uintptr_t)sock
, (const void **)&memory
)) {
2264 if (useExistingInstance
) {
2265 __CFSpinUnlock(&__CFAllSocketsLock
);
2269 #if defined(LOG_CFSOCKET)
2270 fprintf(stdout
, "useExistingInstance is FALSE, removing existing instance %p from __CFAllSockets\n", memory
);
2272 __CFSpinUnlock(&__CFAllSocketsLock
);
2273 CFSocketInvalidate(memory
);
2274 __CFSpinLock(&__CFAllSocketsLock
);
2277 memory
= (CFSocketRef
)_CFRuntimeCreateInstance(allocator
, CFSocketGetTypeID(), sizeof(struct __CFSocket
) - sizeof(CFRuntimeBase
), NULL
);
2278 if (NULL
== memory
) {
2279 __CFSpinUnlock(&__CFAllSocketsLock
);
2282 __CFSocketSetCallBackTypes(memory
, callBackTypes
);
2283 if (INVALID_SOCKET
!= sock
) __CFSocketSetValid(memory
);
2284 __CFSocketUnsetWriteSignalled(memory
);
2285 __CFSocketUnsetReadSignalled(memory
);
2286 memory
->_f
.client
= ((callBackTypes
& (~kCFSocketConnectCallBack
)) & (~kCFSocketWriteCallBack
)) | kCFSocketCloseOnInvalidate
;
2287 memory
->_f
.disabled
= 0;
2288 memory
->_f
.connected
= FALSE
;
2289 memory
->_f
.writableHint
= FALSE
;
2290 memory
->_f
.closeSignaled
= FALSE
;
2291 memory
->_lock
= CFSpinLockInit
;
2292 memory
->_writeLock
= CFSpinLockInit
;
2293 memory
->_socket
= sock
;
2294 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
2295 memory
->_errorCode
= 0;
2296 memory
->_address
= NULL
;
2297 memory
->_peerAddress
= NULL
;
2298 memory
->_socketSetCount
= 0;
2299 memory
->_source0
= NULL
;
2300 if (INVALID_SOCKET
!= sock
) {
2301 memory
->_runLoops
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
);
2303 memory
->_runLoops
= NULL
;
2305 memory
->_callout
= callout
;
2306 memory
->_dataQueue
= NULL
;
2307 memory
->_addressQueue
= NULL
;
2308 memory
->_context
.info
= 0;
2309 memory
->_context
.retain
= 0;
2310 memory
->_context
.release
= 0;
2311 memory
->_context
.copyDescription
= 0;
2312 timerclear(&memory
->_readBufferTimeout
);
2313 memory
->_readBuffer
= NULL
;
2314 memory
->_bytesToBuffer
= 0;
2315 memory
->_bytesToBufferPos
= 0;
2316 memory
->_bytesToBufferReadPos
= 0;
2317 memory
->_atEOF
= false;
2318 memory
->_bufferedReadError
= 0;
2319 memory
->_leftoverBytes
= NULL
;
2321 if (INVALID_SOCKET
!= sock
) CFDictionaryAddValue(__CFAllSockets
, (void *)(uintptr_t)sock
, memory
);
2322 if (NULL
== __CFSocketManagerThread
) __CFSocketManagerThread
= __CFStartSimpleThread(__CFSocketManager
, 0);
2323 __CFSpinUnlock(&__CFAllSocketsLock
);
2324 if (NULL
!= context
) {
2325 void *contextInfo
= context
->retain
? (void *)context
->retain(context
->info
) : context
->info
;
2326 __CFSocketLock(memory
);
2327 memory
->_context
.retain
= context
->retain
;
2328 memory
->_context
.release
= context
->release
;
2329 memory
->_context
.copyDescription
= context
->copyDescription
;
2330 memory
->_context
.info
= contextInfo
;
2331 __CFSocketUnlock(memory
);
2333 #if defined(LOG_CFSOCKET)
2334 CFLog(5, CFSTR("CFSocketCreateWithNative(): created socket %p (%d) with callbacks 0x%x"), memory
, memory
->_socket
, callBackTypes
);
2339 CFSocketRef
CFSocketCreateWithNative(CFAllocatorRef allocator
, CFSocketNativeHandle sock
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
) {
2340 return _CFSocketCreateWithNative(allocator
, sock
, callBackTypes
, callout
, context
, TRUE
);
2343 void CFSocketInvalidate(CFSocketRef s
) {
2344 // CFLog(5, CFSTR("CFSocketInvalidate(%p) starting"), s);
2346 UInt32 previousSocketManagerIteration
;
2347 __CFGenericValidateType(s
, CFSocketGetTypeID());
2348 #if defined(LOG_CFSOCKET)
2349 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
);
2352 __CFSpinLock(&__CFAllSocketsLock
);
2354 if (__CFSocketIsValid(s
)) {
2356 CFRunLoopSourceRef source0
;
2357 void *contextInfo
= NULL
;
2358 void (*contextRelease
)(const void *info
) = NULL
;
2359 __CFSocketUnsetValid(s
);
2360 __CFSocketUnsetWriteSignalled(s
);
2361 __CFSocketUnsetReadSignalled(s
);
2362 __CFSpinLock(&__CFActiveSocketsLock
);
2363 idx
= CFArrayGetFirstIndexOfValue(__CFWriteSockets
, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets
)), s
);
2365 CFArrayRemoveValueAtIndex(__CFWriteSockets
, idx
);
2366 __CFSocketClearFDForWrite(s
);
2368 // No need to clear FD's for V1 sources, since we'll just throw the whole event away
2369 idx
= CFArrayGetFirstIndexOfValue(__CFReadSockets
, CFRangeMake(0, CFArrayGetCount(__CFReadSockets
)), s
);
2371 CFArrayRemoveValueAtIndex(__CFReadSockets
, idx
);
2372 __CFSocketClearFDForRead(s
);
2374 previousSocketManagerIteration
= __CFSocketManagerIteration
;
2375 __CFSpinUnlock(&__CFActiveSocketsLock
);
2376 CFDictionaryRemoveValue(__CFAllSockets
, (void *)(uintptr_t)(s
->_socket
));
2377 if ((s
->_f
.client
& kCFSocketCloseOnInvalidate
) != 0) closesocket(s
->_socket
);
2378 s
->_socket
= INVALID_SOCKET
;
2379 if (NULL
!= s
->_peerAddress
) {
2380 CFRelease(s
->_peerAddress
);
2381 s
->_peerAddress
= NULL
;
2383 if (NULL
!= s
->_dataQueue
) {
2384 CFRelease(s
->_dataQueue
);
2385 s
->_dataQueue
= NULL
;
2387 if (NULL
!= s
->_addressQueue
) {
2388 CFRelease(s
->_addressQueue
);
2389 s
->_addressQueue
= NULL
;
2391 s
->_socketSetCount
= 0;
2392 for (idx
= CFArrayGetCount(s
->_runLoops
); idx
--;) {
2393 CFRunLoopWakeUp((CFRunLoopRef
)CFArrayGetValueAtIndex(s
->_runLoops
, idx
));
2395 CFRelease(s
->_runLoops
);
2396 s
->_runLoops
= NULL
;
2397 source0
= s
->_source0
;
2399 contextInfo
= s
->_context
.info
;
2400 contextRelease
= s
->_context
.release
;
2401 s
->_context
.info
= 0;
2402 s
->_context
.retain
= 0;
2403 s
->_context
.release
= 0;
2404 s
->_context
.copyDescription
= 0;
2405 __CFSocketUnlock(s
);
2406 if (NULL
!= contextRelease
) {
2407 contextRelease(contextInfo
);
2409 if (NULL
!= source0
) {
2410 CFRunLoopSourceInvalidate(source0
);
2414 __CFSocketUnlock(s
);
2416 __CFSpinUnlock(&__CFAllSocketsLock
);
2418 #if defined(LOG_CFSOCKET)
2419 CFLog(5, CFSTR("CFSocketInvalidate(%p) done"), s
);
2423 Boolean
CFSocketIsValid(CFSocketRef s
) {
2425 __CFGenericValidateType(s
, CFSocketGetTypeID());
2426 return __CFSocketIsValid(s
);
2429 CFSocketNativeHandle
CFSocketGetNative(CFSocketRef s
) {
2431 __CFGenericValidateType(s
, CFSocketGetTypeID());
2435 CFDataRef
CFSocketCopyAddress(CFSocketRef s
) {
2437 CFDataRef result
= NULL
;
2438 __CFGenericValidateType(s
, CFSocketGetTypeID());
2440 __CFSocketEstablishAddress(s
);
2441 if (NULL
!= s
->_address
) {
2442 result
= (CFDataRef
)CFRetain(s
->_address
);
2444 __CFSocketUnlock(s
);
2445 #if defined(LOG_CFSOCKET)
2446 CFLog(5, CFSTR("CFSocketCopyAddress(): created socket %p address %@"), s
, result
);
2451 CFDataRef
CFSocketCopyPeerAddress(CFSocketRef s
) {
2453 CFDataRef result
= NULL
;
2454 __CFGenericValidateType(s
, CFSocketGetTypeID());
2456 __CFSocketEstablishPeerAddress(s
);
2457 if (NULL
!= s
->_peerAddress
) {
2458 result
= (CFDataRef
)CFRetain(s
->_peerAddress
);
2460 __CFSocketUnlock(s
);
2461 #if defined(LOG_CFSOCKET)
2462 CFLog(5, CFSTR("CFSocketCopyAddress(): created socket %p peer address %@"), s
, result
);
2467 void CFSocketGetContext(CFSocketRef s
, CFSocketContext
*context
) {
2469 __CFGenericValidateType(s
, CFSocketGetTypeID());
2470 CFAssert1(0 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__
);
2471 *context
= s
->_context
;
2474 CFOptionFlags
CFSocketGetSocketFlags(CFSocketRef s
) {
2476 __CFGenericValidateType(s
, CFSocketGetTypeID());
2477 return s
->_f
.client
;
2480 void CFSocketSetSocketFlags(CFSocketRef s
, CFOptionFlags flags
) {
2482 __CFGenericValidateType(s
, CFSocketGetTypeID());
2484 #if defined(LOG_CFSOCKET)
2485 fprintf(stdout
, "setting flags for socket %d, from 0x%x to 0x%lx\n", s
->_socket
, s
->_f
.client
, flags
);
2487 s
->_f
.client
= flags
;
2488 __CFSocketUnlock(s
);
2489 // CFLog(5, CFSTR("CFSocketSetSocketFlags(%p, 0x%x)"), s, flags);
2492 void CFSocketDisableCallBacks(CFSocketRef s
, CFOptionFlags callBackTypes
) {
2494 Boolean wakeup
= false;
2495 uint8_t readCallBackType
;
2496 __CFGenericValidateType(s
, CFSocketGetTypeID());
2498 if (__CFSocketIsValid(s
) && __CFSocketIsScheduled(s
)) {
2499 callBackTypes
&= __CFSocketCallBackTypes(s
);
2500 readCallBackType
= __CFSocketReadCallBackType(s
);
2501 s
->_f
.disabled
|= callBackTypes
;
2502 #if defined(LOG_CFSOCKET)
2503 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
);
2505 __CFSpinLock(&__CFActiveSocketsLock
);
2506 if ((readCallBackType
== kCFSocketAcceptCallBack
) || !__CFSocketIsConnectionOriented(s
)) s
->_f
.connected
= TRUE
;
2507 if (((callBackTypes
& kCFSocketWriteCallBack
) != 0) || (((callBackTypes
& kCFSocketConnectCallBack
) != 0) && !s
->_f
.connected
)) {
2508 if (__CFSocketClearFDForWrite(s
)) {
2509 // do not wake up the socket manager thread if all relevant write callbacks are disabled
2510 CFOptionFlags writeCallBacksAvailable
= __CFSocketCallBackTypes(s
) & (kCFSocketWriteCallBack
| kCFSocketConnectCallBack
);
2511 if (s
->_f
.connected
) writeCallBacksAvailable
&= ~kCFSocketConnectCallBack
;
2512 if ((s
->_f
.disabled
& writeCallBacksAvailable
) != writeCallBacksAvailable
) wakeup
= true;
2515 if (readCallBackType
!= kCFSocketNoCallBack
&& (callBackTypes
& readCallBackType
) != 0) {
2516 if (__CFSocketClearFDForRead(s
)) {
2517 // do not wake up the socket manager thread if callback type is read
2518 if (readCallBackType
!= kCFSocketReadCallBack
) wakeup
= true;
2521 __CFSpinUnlock(&__CFActiveSocketsLock
);
2523 __CFSocketUnlock(s
);
2526 // "force" means to clear the disabled bits set by DisableCallBacks and always reenable.
2527 // if (!force) we respect those bits, meaning they may stop us from enabling.
2528 // In addition, if !force we assume that the sockets have already been added to the
2529 // __CFReadSockets and __CFWriteSockets arrays. This is true because the callbacks start
2530 // enabled when the CFSocket is created (at which time we enable with force).
2531 // Called with SocketLock held, returns with it released!
2532 void __CFSocketEnableCallBacks(CFSocketRef s
, CFOptionFlags callBackTypes
, Boolean force
, uint8_t wakeupChar
) {
2534 Boolean wakeup
= FALSE
;
2535 if (!callBackTypes
) {
2536 __CFSocketUnlock(s
);
2539 if (__CFSocketIsValid(s
) && __CFSocketIsScheduled(s
)) {
2540 Boolean turnOnWrite
= FALSE
, turnOnConnect
= FALSE
, turnOnRead
= FALSE
;
2541 uint8_t readCallBackType
= __CFSocketReadCallBackType(s
);
2542 callBackTypes
&= __CFSocketCallBackTypes(s
);
2543 if (force
) s
->_f
.disabled
&= ~callBackTypes
;
2544 #if defined(LOG_CFSOCKET)
2545 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
);
2547 /* We will wait for connection only for connection-oriented, non-rendezvous sockets that are not already connected. Mark others as already connected. */
2548 if ((readCallBackType
== kCFSocketAcceptCallBack
) || !__CFSocketIsConnectionOriented(s
)) s
->_f
.connected
= TRUE
;
2550 // First figure out what to turn on
2551 if (s
->_f
.connected
|| (callBackTypes
& kCFSocketConnectCallBack
) == 0) {
2552 // if we want write callbacks and they're not disabled...
2553 if ((callBackTypes
& kCFSocketWriteCallBack
) != 0 && (s
->_f
.disabled
& kCFSocketWriteCallBack
) == 0) turnOnWrite
= TRUE
;
2555 // if we want connect callbacks and they're not disabled...
2556 if ((callBackTypes
& kCFSocketConnectCallBack
) != 0 && (s
->_f
.disabled
& kCFSocketConnectCallBack
) == 0) turnOnConnect
= TRUE
;
2558 // if we want read callbacks and they're not disabled...
2559 if (readCallBackType
!= kCFSocketNoCallBack
&& (callBackTypes
& readCallBackType
) != 0 && (s
->_f
.disabled
& kCFSocketReadCallBack
) == 0) turnOnRead
= TRUE
;
2561 // Now turn on the callbacks we've determined that we want on
2562 if (turnOnRead
|| turnOnWrite
|| turnOnConnect
) {
2563 __CFSpinLock(&__CFActiveSocketsLock
);
2564 if (turnOnWrite
|| turnOnConnect
) {
2566 SInt32 idx
= CFArrayGetFirstIndexOfValue(__CFWriteSockets
, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets
)), s
);
2567 if (kCFNotFound
== idx
) CFArrayAppendValue(__CFWriteSockets
, s
);
2568 // if (kCFNotFound == idx) CFLog(5, CFSTR("__CFSocketEnableCallBacks: put %p in __CFWriteSockets list due to force and non-presence"), s);
2570 if (__CFSocketSetFDForWrite(s
)) wakeup
= true;
2574 SInt32 idx
= CFArrayGetFirstIndexOfValue(__CFReadSockets
, CFRangeMake(0, CFArrayGetCount(__CFReadSockets
)), s
);
2575 if (kCFNotFound
== idx
) CFArrayAppendValue(__CFReadSockets
, s
);
2577 if (__CFSocketSetFDForRead(s
)) wakeup
= true;
2579 __CFSpinUnlock(&__CFActiveSocketsLock
);
2582 __CFSocketUnlock(s
);
2585 void CFSocketEnableCallBacks(CFSocketRef s
, CFOptionFlags callBackTypes
) {
2587 __CFGenericValidateType(s
, CFSocketGetTypeID());
2589 __CFSocketEnableCallBacks(s
, callBackTypes
, TRUE
, 'r');
2590 // CFLog(5, CFSTR("CFSocketEnableCallBacks(%p, 0x%x) done"), s, callBackTypes);
2593 static void __CFSocketSchedule(void *info
, CFRunLoopRef rl
, CFStringRef mode
) {
2594 CFSocketRef s
= (CFSocketRef
)info
;
2596 //??? also need to arrange delivery of all pending data
2597 if (__CFSocketIsValid(s
)) {
2598 CFMutableArrayRef runLoopsOrig
= s
->_runLoops
;
2599 CFMutableArrayRef runLoopsCopy
= CFArrayCreateMutableCopy(kCFAllocatorSystemDefault
, 0, s
->_runLoops
);
2600 CFArrayAppendValue(runLoopsCopy
, rl
);
2601 s
->_runLoops
= runLoopsCopy
;
2602 CFRelease(runLoopsOrig
);
2603 s
->_socketSetCount
++;
2604 // Since the v0 source is listened to on the SocketMgr thread, no matter how many modes it
2605 // is added to we just need to enable it there once (and _socketSetCount gives us a refCount
2606 // to know when we can finally disable it).
2607 if (1 == s
->_socketSetCount
) {
2608 #if defined(LOG_CFSOCKET)
2609 fprintf(stdout
, "scheduling socket %d\n", s
->_socket
);
2611 // CFLog(5, CFSTR("__CFSocketSchedule(%p, %p, %p)"), s, rl, mode);
2612 __CFSocketEnableCallBacks(s
, __CFSocketCallBackTypes(s
), TRUE
, 's'); // unlocks s
2614 __CFSocketUnlock(s
);
2616 __CFSocketUnlock(s
);
2619 static void __CFSocketCancel(void *info
, CFRunLoopRef rl
, CFStringRef mode
) {
2620 CFSocketRef s
= (CFSocketRef
)info
;
2623 s
->_socketSetCount
--;
2624 if (0 == s
->_socketSetCount
) {
2625 __CFSpinLock(&__CFActiveSocketsLock
);
2626 idx
= CFArrayGetFirstIndexOfValue(__CFWriteSockets
, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets
)), s
);
2628 // CFLog(5, CFSTR("__CFSocketCancel: removing %p from __CFWriteSockets list"), s);
2629 CFArrayRemoveValueAtIndex(__CFWriteSockets
, idx
);
2630 __CFSocketClearFDForWrite(s
);
2632 idx
= CFArrayGetFirstIndexOfValue(__CFReadSockets
, CFRangeMake(0, CFArrayGetCount(__CFReadSockets
)), s
);
2634 CFArrayRemoveValueAtIndex(__CFReadSockets
, idx
);
2635 __CFSocketClearFDForRead(s
);
2637 __CFSpinUnlock(&__CFActiveSocketsLock
);
2639 if (NULL
!= s
->_runLoops
) {
2640 CFMutableArrayRef runLoopsOrig
= s
->_runLoops
;
2641 CFMutableArrayRef runLoopsCopy
= CFArrayCreateMutableCopy(kCFAllocatorSystemDefault
, 0, s
->_runLoops
);
2642 idx
= CFArrayGetFirstIndexOfValue(runLoopsCopy
, CFRangeMake(0, CFArrayGetCount(runLoopsCopy
)), rl
);
2643 if (0 <= idx
) CFArrayRemoveValueAtIndex(runLoopsCopy
, idx
);
2644 s
->_runLoops
= runLoopsCopy
;
2645 CFRelease(runLoopsOrig
);
2647 __CFSocketUnlock(s
);
2650 // Note: must be called with socket lock held, then returns with it released
2651 // Used by both the v0 and v1 RunLoopSource perform routines
2652 static void __CFSocketDoCallback(CFSocketRef s
, CFDataRef data
, CFDataRef address
, CFSocketNativeHandle sock
) {
2653 CFSocketCallBack callout
= NULL
;
2654 void *contextInfo
= NULL
;
2655 SInt32 errorCode
= 0;
2656 Boolean readSignalled
= false, writeSignalled
= false, connectSignalled
= false, calledOut
= false;
2657 uint8_t readCallBackType
, callBackTypes
;
2659 callBackTypes
= __CFSocketCallBackTypes(s
);
2660 readCallBackType
= __CFSocketReadCallBackType(s
);
2661 readSignalled
= __CFSocketIsReadSignalled(s
);
2662 writeSignalled
= __CFSocketIsWriteSignalled(s
);
2663 connectSignalled
= writeSignalled
&& !s
->_f
.connected
;
2664 __CFSocketUnsetReadSignalled(s
);
2665 __CFSocketUnsetWriteSignalled(s
);
2666 callout
= s
->_callout
;
2667 contextInfo
= s
->_context
.info
;
2668 #if defined(LOG_CFSOCKET)
2669 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
);
2671 if (writeSignalled
) {
2672 errorCode
= s
->_errorCode
;
2673 s
->_f
.connected
= TRUE
;
2675 __CFSocketUnlock(s
);
2676 if ((callBackTypes
& kCFSocketConnectCallBack
) != 0) {
2677 if (connectSignalled
&& (!calledOut
|| CFSocketIsValid(s
))) {
2678 // CFLog(5, CFSTR("__CFSocketPerformV0(%p) doing connect callback, error: %d"), s, errorCode);
2680 #if defined(LOG_CFSOCKET)
2681 fprintf(stdout
, "perform calling out error %ld to socket %d\n", (long)errorCode
, s
->_socket
);
2683 if (callout
) callout(s
, kCFSocketConnectCallBack
, NULL
, &errorCode
, contextInfo
);
2686 #if defined(LOG_CFSOCKET)
2687 fprintf(stdout
, "perform calling out connect to socket %d\n", s
->_socket
);
2689 if (callout
) callout(s
, kCFSocketConnectCallBack
, NULL
, NULL
, contextInfo
);
2694 if (kCFSocketDataCallBack
== readCallBackType
) {
2695 if (NULL
!= data
&& (!calledOut
|| CFSocketIsValid(s
))) {
2696 SInt32 datalen
= CFDataGetLength(data
);
2697 #if defined(LOG_CFSOCKET)
2698 fprintf(stdout
, "perform calling out data of length %ld to socket %d\n", (long)datalen
, s
->_socket
);
2700 if (callout
) callout(s
, kCFSocketDataCallBack
, address
, data
, contextInfo
);
2702 if (0 == datalen
) CFSocketInvalidate(s
);
2704 } else if (kCFSocketAcceptCallBack
== readCallBackType
) {
2705 if (INVALID_SOCKET
!= sock
&& (!calledOut
|| CFSocketIsValid(s
))) {
2706 #if defined(LOG_CFSOCKET)
2707 fprintf(stdout
, "perform calling out accept of socket %d to socket %d\n", sock
, s
->_socket
);
2709 if (callout
) callout(s
, kCFSocketAcceptCallBack
, address
, &sock
, contextInfo
);
2712 } else if (kCFSocketReadCallBack
== readCallBackType
) {
2713 if (readSignalled
&& (!calledOut
|| CFSocketIsValid(s
))) {
2714 #if defined(LOG_CFSOCKET)
2715 fprintf(stdout
, "perform calling out read to socket %d\n", s
->_socket
);
2717 // CFLog(5, CFSTR("__CFSocketPerformV0(%p) doing read callback"), s);
2718 if (callout
) callout(s
, kCFSocketReadCallBack
, NULL
, NULL
, contextInfo
);
2722 if ((callBackTypes
& kCFSocketWriteCallBack
) != 0) {
2723 if (writeSignalled
&& !errorCode
&& (!calledOut
|| CFSocketIsValid(s
))) {
2724 #if defined(LOG_CFSOCKET)
2725 fprintf(stdout
, "perform calling out write to socket %d\n", s
->_socket
);
2727 // CFLog(5, CFSTR("__CFSocketPerformV0(%p) doing write callback"), s);
2728 if (callout
) callout(s
, kCFSocketWriteCallBack
, NULL
, NULL
, contextInfo
);
2734 static void __CFSocketPerformV0(void *info
) {
2735 CFSocketRef s
= (CFSocketRef
)info
;
2736 CFDataRef data
= NULL
;
2737 CFDataRef address
= NULL
;
2738 CFSocketNativeHandle sock
= INVALID_SOCKET
;
2739 uint8_t readCallBackType
, callBackTypes
;
2740 CFRunLoopRef rl
= NULL
;
2741 // CFLog(5, CFSTR("__CFSocketPerformV0(%p) starting"), s);
2744 if (!__CFSocketIsValid(s
)) {
2745 __CFSocketUnlock(s
);
2748 callBackTypes
= __CFSocketCallBackTypes(s
);
2749 readCallBackType
= __CFSocketReadCallBackType(s
);
2750 CFOptionFlags callBacksSignalled
= 0;
2751 if (__CFSocketIsReadSignalled(s
)) callBacksSignalled
|= readCallBackType
;
2752 if (__CFSocketIsWriteSignalled(s
)) callBacksSignalled
|= kCFSocketWriteCallBack
;
2754 if (kCFSocketDataCallBack
== readCallBackType
) {
2755 if (NULL
!= s
->_dataQueue
&& 0 < CFArrayGetCount(s
->_dataQueue
)) {
2756 data
= (CFDataRef
)CFArrayGetValueAtIndex(s
->_dataQueue
, 0);
2758 CFArrayRemoveValueAtIndex(s
->_dataQueue
, 0);
2759 address
= (CFDataRef
)CFArrayGetValueAtIndex(s
->_addressQueue
, 0);
2761 CFArrayRemoveValueAtIndex(s
->_addressQueue
, 0);
2763 } else if (kCFSocketAcceptCallBack
== readCallBackType
) {
2764 if (NULL
!= s
->_dataQueue
&& 0 < CFArrayGetCount(s
->_dataQueue
)) {
2765 sock
= (CFSocketNativeHandle
)(uintptr_t)CFArrayGetValueAtIndex(s
->_dataQueue
, 0);
2766 CFArrayRemoveValueAtIndex(s
->_dataQueue
, 0);
2767 address
= (CFDataRef
)CFArrayGetValueAtIndex(s
->_addressQueue
, 0);
2769 CFArrayRemoveValueAtIndex(s
->_addressQueue
, 0);
2773 __CFSocketDoCallback(s
, data
, address
, sock
); // does __CFSocketUnlock(s)
2774 if (NULL
!= data
) CFRelease(data
);
2775 if (NULL
!= address
) CFRelease(address
);
2778 if (__CFSocketIsValid(s
) && kCFSocketNoCallBack
!= readCallBackType
) {
2779 // if there's still more data, we want to wake back up right away
2780 if ((kCFSocketDataCallBack
== readCallBackType
|| kCFSocketAcceptCallBack
== readCallBackType
) && NULL
!= s
->_dataQueue
&& 0 < CFArrayGetCount(s
->_dataQueue
)) {
2781 #if defined(LOG_CFSOCKET)
2782 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
);
2784 CFRunLoopSourceSignal(s
->_source0
);
2785 CFMutableArrayRef runLoopsOrig
= (CFMutableArrayRef
)CFRetain(s
->_runLoops
);
2786 CFMutableArrayRef runLoopsCopy
= CFArrayCreateMutableCopy(kCFAllocatorSystemDefault
, 0, s
->_runLoops
);
2787 CFRunLoopSourceRef source0
= s
->_source0
;
2788 if (NULL
!= source0
&& !CFRunLoopSourceIsValid(source0
)) {
2791 if (source0
) CFRetain(source0
);
2792 __CFSocketUnlock(s
);
2793 rl
= __CFSocketCopyRunLoopToWakeUp(source0
, runLoopsCopy
);
2794 if (source0
) CFRelease(source0
);
2796 if (runLoopsOrig
== s
->_runLoops
) {
2797 s
->_runLoops
= runLoopsCopy
;
2798 runLoopsCopy
= NULL
;
2799 CFRelease(runLoopsOrig
);
2801 CFRelease(runLoopsOrig
);
2802 if (runLoopsCopy
) CFRelease(runLoopsCopy
);
2805 // Only reenable callbacks that are auto-reenabled
2806 __CFSocketEnableCallBacks(s
, callBacksSignalled
& s
->_f
.client
, FALSE
, 'p'); // unlocks s
2809 CFRunLoopWakeUp(rl
);
2812 // CFLog(5, CFSTR("__CFSocketPerformV0(%p) done"), s);
2815 CFRunLoopSourceRef
CFSocketCreateRunLoopSource(CFAllocatorRef allocator
, CFSocketRef s
, CFIndex order
) {
2817 CFRunLoopSourceRef result
= NULL
;
2818 __CFGenericValidateType(s
, CFSocketGetTypeID());
2820 if (__CFSocketIsValid(s
)) {
2821 if (NULL
!= s
->_source0
&& !CFRunLoopSourceIsValid(s
->_source0
)) {
2822 CFRelease(s
->_source0
);
2825 if (NULL
== s
->_source0
) {
2826 CFRunLoopSourceContext context
;
2827 context
.version
= 0;
2829 context
.retain
= CFRetain
;
2830 context
.release
= CFRelease
;
2831 context
.copyDescription
= CFCopyDescription
;
2832 context
.equal
= CFEqual
;
2833 context
.hash
= CFHash
;
2834 context
.schedule
= __CFSocketSchedule
;
2835 context
.cancel
= __CFSocketCancel
;
2836 context
.perform
= __CFSocketPerformV0
;
2837 s
->_source0
= CFRunLoopSourceCreate(allocator
, order
, &context
);
2839 CFRetain(s
->_source0
); /* This retain is for the receiver */
2840 result
= s
->_source0
;
2842 __CFSocketUnlock(s
);
2846 #endif /* NEW_SOCKET */
2850 static uint16_t __CFSocketDefaultNameRegistryPortNumber
= 2454;
2852 CONST_STRING_DECL(kCFSocketCommandKey
, "Command")
2853 CONST_STRING_DECL(kCFSocketNameKey
, "Name")
2854 CONST_STRING_DECL(kCFSocketValueKey
, "Value")
2855 CONST_STRING_DECL(kCFSocketResultKey
, "Result")
2856 CONST_STRING_DECL(kCFSocketErrorKey
, "Error")
2857 CONST_STRING_DECL(kCFSocketRegisterCommand
, "Register")
2858 CONST_STRING_DECL(kCFSocketRetrieveCommand
, "Retrieve")
2859 CONST_STRING_DECL(__kCFSocketRegistryRequestRunLoopMode
, "CFSocketRegistryRequest")
2861 static CFSpinLock_t __CFSocketWriteLock_
= CFSpinLockInit
;
2862 //#warning can only send on one socket at a time now
2864 CF_INLINE
void __CFSocketWriteLock(CFSocketRef s
) {
2865 __CFSpinLock(& __CFSocketWriteLock_
);
2868 CF_INLINE
void __CFSocketWriteUnlock(CFSocketRef s
) {
2869 __CFSpinUnlock(& __CFSocketWriteLock_
);
2874 CF_INLINE CFIndex
__CFSocketFdGetSize(CFDataRef fdSet
) {
2875 return NBBY
* CFDataGetLength(fdSet
);
2878 CF_INLINE Boolean
__CFSocketFdSet(CFSocketNativeHandle sock
, CFMutableDataRef fdSet
) {
2879 /* returns true if a change occurred, false otherwise */
2880 Boolean retval
= false;
2881 if (INVALID_SOCKET
!= sock
&& 0 <= sock
) {
2882 CFIndex numFds
= NBBY
* CFDataGetLength(fdSet
);
2884 if (sock
>= numFds
) {
2885 CFIndex oldSize
= numFds
/ NFDBITS
, newSize
= (sock
+ NFDBITS
) / NFDBITS
, changeInBytes
= (newSize
- oldSize
) * sizeof(fd_mask
);
2886 CFDataIncreaseLength(fdSet
, changeInBytes
);
2887 fds_bits
= (fd_mask
*)CFDataGetMutableBytePtr(fdSet
);
2888 memset(fds_bits
+ oldSize
, 0, changeInBytes
);
2890 fds_bits
= (fd_mask
*)CFDataGetMutableBytePtr(fdSet
);
2892 if (!FD_ISSET(sock
, (fd_set
*)fds_bits
)) {
2894 FD_SET(sock
, (fd_set
*)fds_bits
);
2902 //??? need timeout, error handling, retries
2903 CFSocketError
CFSocketSendData(CFSocketRef s
, CFDataRef address
, CFDataRef data
, CFTimeInterval timeout
) {
2905 const uint8_t *dataptr
, *addrptr
= NULL
;
2906 SInt32 datalen
, addrlen
= 0, size
= 0;
2907 CFSocketNativeHandle sock
= INVALID_SOCKET
;
2909 __CFGenericValidateType(s
, CFSocketGetTypeID());
2911 addrptr
= CFDataGetBytePtr(address
);
2912 addrlen
= CFDataGetLength(address
);
2914 dataptr
= CFDataGetBytePtr(data
);
2915 datalen
= CFDataGetLength(data
);
2916 if (CFSocketIsValid(s
)) sock
= CFSocketGetNative(s
);
2917 if (INVALID_SOCKET
!= sock
) {
2919 __CFSocketWriteLock(s
);
2920 tv
.tv_sec
= (timeout
<= 0.0 || (CFTimeInterval
)INT_MAX
<= timeout
) ? INT_MAX
: (int)floor(timeout
);
2921 tv
.tv_usec
= (int)floor(1.0e+6 * (timeout
- floor(timeout
)));
2922 setsockopt(sock
, SOL_SOCKET
, SO_SNDTIMEO
, (char *)&tv
, sizeof(tv
)); // cast for WinSock bad API
2923 if (NULL
!= addrptr
&& 0 < addrlen
) {
2924 size
= sendto(sock
, (char *)dataptr
, datalen
, 0, (struct sockaddr
*)addrptr
, addrlen
);
2926 size
= send(sock
, (char *)dataptr
, datalen
, 0);
2928 #if defined(LOG_CFSOCKET)
2929 fprintf(stdout
, "wrote %ld bytes to socket %d\n", (long)size
, sock
);
2931 __CFSocketWriteUnlock(s
);
2934 return (size
> 0) ? kCFSocketSuccess
: kCFSocketError
;
2937 CFSocketError
CFSocketSetAddress(CFSocketRef s
, CFDataRef address
) {
2939 struct sockaddr
*name
;
2941 __CFGenericValidateType(s
, CFSocketGetTypeID());
2942 if (NULL
== address
) return kCFSocketError
;
2943 if (!CFSocketIsValid(s
)) return kCFSocketError
;
2945 name
= (struct sockaddr
*)CFDataGetBytePtr(address
);
2946 namelen
= (socklen_t
)CFDataGetLength(address
);
2947 if (!name
|| namelen
<= 0) return kCFSocketError
;
2949 CFSocketNativeHandle sock
= CFSocketGetNative(s
);
2950 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2951 // 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.
2952 // Max size is a size byte, plus family byte, plus path of 255, plus a null byte.
2954 if (namelen
> 2 && name
->sa_family
== AF_UNIX
) {
2955 // 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)
2956 socklen_t realLength
= (sizeof(*((struct sockaddr_un
*)name
)) - sizeof(((struct sockaddr_un
*)name
)->sun_path
) + strnlen(((struct sockaddr_un
*)name
)->sun_path
, namelen
- 2));
2957 if (realLength
> 255) return kCFSocketError
;
2959 // 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.
2960 namelen
= (socklen_t
)(((struct sockaddr_un
*)name
)->sun_len
);
2962 if (realLength
!= namelen
) {
2963 // 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.
2964 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."));
2965 memcpy(newName
, name
, realLength
);
2966 namelen
= realLength
;
2967 ((struct sockaddr_un
*)newName
)->sun_len
= realLength
;
2968 name
= (struct sockaddr
*)newName
;
2972 int result
= bind(sock
, name
, namelen
);
2976 //??? should return errno
2977 return (CFIndex
)result
;
2980 CFSocketError
CFSocketConnectToAddress(CFSocketRef s
, CFDataRef address
, CFTimeInterval timeout
) {
2982 //??? need error handling, retries
2983 const uint8_t *name
;
2984 SInt32 namelen
, result
= -1, connect_err
= 0, select_err
= 0;
2985 UInt32 yes
= 1, no
= 0;
2986 Boolean wasBlocking
= true;
2988 __CFGenericValidateType(s
, CFSocketGetTypeID());
2989 if (!CFSocketIsValid(s
)) return kCFSocketError
;
2990 name
= CFDataGetBytePtr(address
);
2991 namelen
= CFDataGetLength(address
);
2992 if (!name
|| namelen
<= 0) return kCFSocketError
;
2993 CFSocketNativeHandle sock
= CFSocketGetNative(s
);
2995 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2996 SInt32 flags
= fcntl(sock
, F_GETFL
, 0);
2997 if (flags
>= 0) wasBlocking
= ((flags
& O_NONBLOCK
) == 0);
2998 if (wasBlocking
&& (timeout
> 0.0 || timeout
< 0.0)) ioctlsocket(sock
, FIONBIO
, (u_long
*)&yes
);
3000 // You can set but not get this flag in WIN32, so assume it was in non-blocking mode.
3001 // The downside is that when we leave this routine we'll leave it non-blocking,
3002 // whether it started that way or not.
3004 if (timeout
> 0.0 || timeout
< 0.0) ioctlsocket(sock
, FIONBIO
, (u_long
*)&yes
);
3005 wasBlocking
= false;
3007 result
= connect(sock
, (struct sockaddr
*)name
, namelen
);
3009 connect_err
= __CFSocketLastError();
3010 #if DEPLOYMENT_TARGET_WINDOWS
3011 if (connect_err
== WSAEWOULDBLOCK
) connect_err
= EINPROGRESS
;
3014 #if defined(LOG_CFSOCKET)
3015 fprintf(stdout
, "connection attempt returns %d error %d on socket %d (flags 0x%x blocking %d)\n", result
, connect_err
, sock
, flags
, wasBlocking
);
3017 if (EINPROGRESS
== connect_err
&& timeout
>= 0.0) {
3018 /* select on socket */
3020 int error_size
= sizeof(select_err
);
3022 CFMutableDataRef fds
= CFDataCreateMutable(kCFAllocatorSystemDefault
, 0);
3023 __CFSocketFdSet(sock
, fds
);
3024 tv
.tv_sec
= (timeout
<= 0.0 || (CFTimeInterval
)INT_MAX
<= timeout
) ? INT_MAX
: (int)floor(timeout
);
3025 tv
.tv_usec
= (int)floor(1.0e+6 * (timeout
- floor(timeout
)));
3026 nrfds
= select(__CFSocketFdGetSize(fds
), NULL
, (fd_set
*)CFDataGetMutableBytePtr(fds
), NULL
, &tv
);
3028 select_err
= __CFSocketLastError();
3030 } else if (nrfds
== 0) {
3033 if (0 != getsockopt(sock
, SOL_SOCKET
, SO_ERROR
, (char *)&select_err
, (socklen_t
*)&error_size
)) select_err
= 0;
3034 result
= (select_err
== 0) ? 0 : -1;
3037 #if defined(LOG_CFSOCKET)
3038 fprintf(stdout
, "timed connection attempt %s on socket %d, result %d, select returns %d error %d\n", (result
== 0) ? "succeeds" : "fails", sock
, result
, nrfds
, select_err
);
3041 if (wasBlocking
&& (timeout
> 0.0 || timeout
< 0.0)) ioctlsocket(sock
, FIONBIO
, (u_long
*)&no
);
3042 if (EINPROGRESS
== connect_err
&& timeout
< 0.0) {
3044 #if defined(LOG_CFSOCKET)
3045 fprintf(stdout
, "connection attempt continues in background on socket %d\n", sock
);
3049 //??? should return errno
3053 CFSocketRef
CFSocketCreate(CFAllocatorRef allocator
, SInt32 protocolFamily
, SInt32 socketType
, SInt32 protocol
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
) {
3055 CFSocketNativeHandle sock
= INVALID_SOCKET
;
3056 CFSocketRef s
= NULL
;
3057 if (0 >= protocolFamily
) protocolFamily
= PF_INET
;
3058 if (PF_INET
== protocolFamily
) {
3059 if (0 >= socketType
) socketType
= SOCK_STREAM
;
3060 if (0 >= protocol
&& SOCK_STREAM
== socketType
) protocol
= IPPROTO_TCP
;
3061 if (0 >= protocol
&& SOCK_DGRAM
== socketType
) protocol
= IPPROTO_UDP
;
3063 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3064 if (PF_LOCAL
== protocolFamily
&& 0 >= socketType
) socketType
= SOCK_STREAM
;
3066 #if DEPLOYMENT_TARGET_WINDOWS
3067 // make sure we've called proper Win32 startup facilities before socket()
3068 __CFSocketInitializeWinSock();
3070 sock
= socket(protocolFamily
, socketType
, protocol
);
3071 if (INVALID_SOCKET
!= sock
) {
3072 s
= CFSocketCreateWithNative(allocator
, sock
, callBackTypes
, callout
, context
);
3077 CFSocketRef
CFSocketCreateWithSocketSignature(CFAllocatorRef allocator
, const CFSocketSignature
*signature
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
) {
3079 CFSocketRef s
= CFSocketCreate(allocator
, signature
->protocolFamily
, signature
->socketType
, signature
->protocol
, callBackTypes
, callout
, context
);
3080 if (NULL
!= s
&& (!CFSocketIsValid(s
) || kCFSocketSuccess
!= CFSocketSetAddress(s
, signature
->address
))) {
3081 CFSocketInvalidate(s
);
3088 CFSocketRef
CFSocketCreateConnectedToSocketSignature(CFAllocatorRef allocator
, const CFSocketSignature
*signature
, CFOptionFlags callBackTypes
, CFSocketCallBack callout
, const CFSocketContext
*context
, CFTimeInterval timeout
) {
3090 CFSocketRef s
= CFSocketCreate(allocator
, signature
->protocolFamily
, signature
->socketType
, signature
->protocol
, callBackTypes
, callout
, context
);
3091 if (NULL
!= s
&& (!CFSocketIsValid(s
) || kCFSocketSuccess
!= CFSocketConnectToAddress(s
, signature
->address
, timeout
))) {
3092 CFSocketInvalidate(s
);
3100 CFSocketError
*error
;
3101 CFPropertyListRef
*value
;
3103 } __CFSocketNameRegistryResponse
;
3105 static void __CFSocketHandleNameRegistryReply(CFSocketRef s
, CFSocketCallBackType type
, CFDataRef address
, const void *data
, void *info
) {
3106 CFDataRef replyData
= (CFDataRef
)data
;
3107 __CFSocketNameRegistryResponse
*response
= (__CFSocketNameRegistryResponse
*)info
;
3108 CFDictionaryRef replyDictionary
= NULL
;
3109 CFPropertyListRef value
;
3110 replyDictionary
= (CFDictionaryRef
)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault
, replyData
, kCFPropertyListImmutable
, NULL
);
3111 if (NULL
!= response
->error
) *(response
->error
) = kCFSocketError
;
3112 if (NULL
!= replyDictionary
) {
3113 if (CFGetTypeID((CFTypeRef
)replyDictionary
) == CFDictionaryGetTypeID() && NULL
!= (value
= CFDictionaryGetValue(replyDictionary
, kCFSocketResultKey
))) {
3114 if (NULL
!= response
->error
) *(response
->error
) = kCFSocketSuccess
;
3115 if (NULL
!= response
->value
) *(response
->value
) = CFRetain(value
);
3116 if (NULL
!= response
->address
) *(response
->address
) = address
? CFDataCreateCopy(kCFAllocatorSystemDefault
, address
) : NULL
;
3118 CFRelease(replyDictionary
);
3120 CFSocketInvalidate(s
);
3123 static void __CFSocketSendNameRegistryRequest(CFSocketSignature
*signature
, CFDictionaryRef requestDictionary
, __CFSocketNameRegistryResponse
*response
, CFTimeInterval timeout
) {
3124 CFDataRef requestData
= NULL
;
3125 CFSocketContext context
= {0, response
, NULL
, NULL
, NULL
};
3126 CFSocketRef s
= NULL
;
3127 CFRunLoopSourceRef source
= NULL
;
3128 if (NULL
!= response
->error
) *(response
->error
) = kCFSocketError
;
3129 requestData
= CFPropertyListCreateXMLData(kCFAllocatorSystemDefault
, requestDictionary
);
3130 if (NULL
!= requestData
) {
3131 if (NULL
!= response
->error
) *(response
->error
) = kCFSocketTimeout
;
3132 s
= CFSocketCreateConnectedToSocketSignature(kCFAllocatorSystemDefault
, signature
, kCFSocketDataCallBack
, __CFSocketHandleNameRegistryReply
, &context
, timeout
);
3134 if (kCFSocketSuccess
== CFSocketSendData(s
, NULL
, requestData
, timeout
)) {
3135 source
= CFSocketCreateRunLoopSource(kCFAllocatorSystemDefault
, s
, 0);
3136 CFRunLoopAddSource(CFRunLoopGetCurrent(), source
, __kCFSocketRegistryRequestRunLoopMode
);
3137 CFRunLoopRunInMode(__kCFSocketRegistryRequestRunLoopMode
, timeout
, false);
3140 CFSocketInvalidate(s
);
3143 CFRelease(requestData
);
3147 static void __CFSocketValidateSignature(const CFSocketSignature
*providedSignature
, CFSocketSignature
*signature
, uint16_t defaultPortNumber
) {
3148 struct sockaddr_in sain
, *sainp
;
3149 memset(&sain
, 0, sizeof(sain
));
3150 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3151 sain
.sin_len
= sizeof(sain
);
3153 sain
.sin_family
= AF_INET
;
3154 sain
.sin_port
= htons(__CFSocketDefaultNameRegistryPortNumber
);
3155 sain
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
3156 if (NULL
== providedSignature
) {
3157 signature
->protocolFamily
= PF_INET
;
3158 signature
->socketType
= SOCK_STREAM
;
3159 signature
->protocol
= IPPROTO_TCP
;
3160 signature
->address
= CFDataCreate(kCFAllocatorSystemDefault
, (uint8_t *)&sain
, sizeof(sain
));
3162 signature
->protocolFamily
= providedSignature
->protocolFamily
;
3163 signature
->socketType
= providedSignature
->socketType
;
3164 signature
->protocol
= providedSignature
->protocol
;
3165 if (0 >= signature
->protocolFamily
) signature
->protocolFamily
= PF_INET
;
3166 if (PF_INET
== signature
->protocolFamily
) {
3167 if (0 >= signature
->socketType
) signature
->socketType
= SOCK_STREAM
;
3168 if (0 >= signature
->protocol
&& SOCK_STREAM
== signature
->socketType
) signature
->protocol
= IPPROTO_TCP
;
3169 if (0 >= signature
->protocol
&& SOCK_DGRAM
== signature
->socketType
) signature
->protocol
= IPPROTO_UDP
;
3171 if (NULL
== providedSignature
->address
) {
3172 signature
->address
= CFDataCreate(kCFAllocatorSystemDefault
, (uint8_t *)&sain
, sizeof(sain
));
3174 sainp
= (struct sockaddr_in
*)CFDataGetBytePtr(providedSignature
->address
);
3175 if ((int)sizeof(struct sockaddr_in
) <= CFDataGetLength(providedSignature
->address
) && (AF_INET
== sainp
->sin_family
|| 0 == sainp
->sin_family
)) {
3176 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3177 sain
.sin_len
= sizeof(sain
);
3179 sain
.sin_family
= AF_INET
;
3180 sain
.sin_port
= sainp
->sin_port
;
3181 if (0 == sain
.sin_port
) sain
.sin_port
= htons(defaultPortNumber
);
3182 sain
.sin_addr
.s_addr
= sainp
->sin_addr
.s_addr
;
3183 if (htonl(INADDR_ANY
) == sain
.sin_addr
.s_addr
) sain
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
3184 signature
->address
= CFDataCreate(kCFAllocatorSystemDefault
, (uint8_t *)&sain
, sizeof(sain
));
3186 signature
->address
= (CFDataRef
)CFRetain(providedSignature
->address
);
3192 CFSocketError
CFSocketRegisterValue(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
, CFPropertyListRef value
) {
3193 CFSocketSignature signature
;
3194 CFMutableDictionaryRef dictionary
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 3, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
3195 CFSocketError retval
= kCFSocketError
;
3196 __CFSocketNameRegistryResponse response
= {&retval
, NULL
, NULL
};
3197 CFDictionaryAddValue(dictionary
, kCFSocketCommandKey
, kCFSocketRegisterCommand
);
3198 CFDictionaryAddValue(dictionary
, kCFSocketNameKey
, name
);
3199 if (NULL
!= value
) CFDictionaryAddValue(dictionary
, kCFSocketValueKey
, value
);
3200 __CFSocketValidateSignature(nameServerSignature
, &signature
, __CFSocketDefaultNameRegistryPortNumber
);
3201 __CFSocketSendNameRegistryRequest(&signature
, dictionary
, &response
, timeout
);
3202 CFRelease(dictionary
);
3203 CFRelease(signature
.address
);
3207 CFSocketError
CFSocketCopyRegisteredValue(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
, CFPropertyListRef
*value
, CFDataRef
*serverAddress
) {
3208 CFSocketSignature signature
;
3209 CFMutableDictionaryRef dictionary
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 2, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
3210 CFSocketError retval
= kCFSocketError
;
3211 __CFSocketNameRegistryResponse response
= {&retval
, value
, serverAddress
};
3212 CFDictionaryAddValue(dictionary
, kCFSocketCommandKey
, kCFSocketRetrieveCommand
);
3213 CFDictionaryAddValue(dictionary
, kCFSocketNameKey
, name
);
3214 __CFSocketValidateSignature(nameServerSignature
, &signature
, __CFSocketDefaultNameRegistryPortNumber
);
3215 __CFSocketSendNameRegistryRequest(&signature
, dictionary
, &response
, timeout
);
3216 CFRelease(dictionary
);
3217 CFRelease(signature
.address
);
3221 CFSocketError
CFSocketRegisterSocketSignature(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
, const CFSocketSignature
*signature
) {
3222 CFSocketSignature validatedSignature
;
3223 CFMutableDataRef data
= NULL
;
3224 CFSocketError retval
;
3227 if (NULL
== signature
) {
3228 retval
= CFSocketUnregister(nameServerSignature
, timeout
, name
);
3230 __CFSocketValidateSignature(signature
, &validatedSignature
, 0);
3231 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
) {
3232 retval
= kCFSocketError
;
3234 data
= CFDataCreateMutable(kCFAllocatorSystemDefault
, sizeof(bytes
) + length
);
3235 bytes
[0] = validatedSignature
.protocolFamily
;
3236 bytes
[1] = validatedSignature
.socketType
;
3237 bytes
[2] = validatedSignature
.protocol
;
3239 CFDataAppendBytes(data
, bytes
, sizeof(bytes
));
3240 CFDataAppendBytes(data
, CFDataGetBytePtr(validatedSignature
.address
), length
);
3241 retval
= CFSocketRegisterValue(nameServerSignature
, timeout
, name
, data
);
3244 CFRelease(validatedSignature
.address
);
3249 CFSocketError
CFSocketCopyRegisteredSocketSignature(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
, CFSocketSignature
*signature
, CFDataRef
*nameServerAddress
) {
3250 CFDataRef data
= NULL
;
3251 CFSocketSignature returnedSignature
;
3252 const uint8_t *ptr
= NULL
, *aptr
= NULL
;
3255 CFDataRef serverAddress
= NULL
;
3256 CFSocketError retval
= CFSocketCopyRegisteredValue(nameServerSignature
, timeout
, name
, (CFPropertyListRef
*)&data
, &serverAddress
);
3257 if (NULL
== data
|| CFGetTypeID(data
) != CFDataGetTypeID() || NULL
== (ptr
= CFDataGetBytePtr(data
)) || (length
= CFDataGetLength(data
)) < 4) retval
= kCFSocketError
;
3258 if (kCFSocketSuccess
== retval
&& NULL
!= signature
) {
3259 returnedSignature
.protocolFamily
= (SInt32
)*ptr
++;
3260 returnedSignature
.socketType
= (SInt32
)*ptr
++;
3261 returnedSignature
.protocol
= (SInt32
)*ptr
++;
3263 returnedSignature
.address
= CFDataCreate(kCFAllocatorSystemDefault
, ptr
, length
- 4);
3264 __CFSocketValidateSignature(&returnedSignature
, signature
, 0);
3265 CFRelease(returnedSignature
.address
);
3266 ptr
= CFDataGetBytePtr(signature
->address
);
3267 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
) {
3268 CFMutableDataRef address
= CFDataCreateMutableCopy(kCFAllocatorSystemDefault
, CFDataGetLength(signature
->address
), signature
->address
);
3269 mptr
= CFDataGetMutableBytePtr(address
);
3270 ((struct sockaddr_in
*)mptr
)->sin_addr
= ((struct sockaddr_in
*)aptr
)->sin_addr
;
3271 CFRelease(signature
->address
);
3272 signature
->address
= address
;
3274 if (NULL
!= nameServerAddress
) *nameServerAddress
= serverAddress
? (CFDataRef
)CFRetain(serverAddress
) : NULL
;
3276 if (NULL
!= data
) CFRelease(data
);
3277 if (NULL
!= serverAddress
) CFRelease(serverAddress
);
3281 CFSocketError
CFSocketUnregister(const CFSocketSignature
*nameServerSignature
, CFTimeInterval timeout
, CFStringRef name
) {
3282 return CFSocketRegisterValue(nameServerSignature
, timeout
, name
, NULL
);
3285 CF_EXPORT
void CFSocketSetDefaultNameRegistryPortNumber(uint16_t port
) {
3286 __CFSocketDefaultNameRegistryPortNumber
= port
;
3289 CF_EXPORT
uint16_t CFSocketGetDefaultNameRegistryPortNumber(void) {
3290 return __CFSocketDefaultNameRegistryPortNumber
;