]> git.saurik.com Git - apple/cf.git/blame - CFSocket.c
CF-550.42.tar.gz
[apple/cf.git] / CFSocket.c
CommitLineData
9ce05555 1/*
e588f561 2 * Copyright (c) 2010 Apple Inc. All rights reserved.
9ce05555
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
9ce05555
A
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
f64f9b69 23
9ce05555 24/* CFSocket.c
7c97c3e0 25 Copyright (c) 1999-2010, Apple Inc. All rights reserved.
f32021b4 26 Responsibility: Christopher Kane
9ce05555
A
27*/
28
cf7d2af9
A
29#define NEW_SOCKET 0
30
31#if NEW_SOCKET
32
33
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>
41#include <sys/stat.h>
7c97c3e0 42#include <unistd.h>
cf7d2af9 43#include <dlfcn.h>
7c97c3e0 44#include <sys/select.h>
cf7d2af9
A
45
46
47extern void _CFRunLoopSourceWakeUpRunLoops(CFRunLoopSourceRef rls);
48
49#define INVALID_SOCKET (CFSocketNativeHandle)(-1)
50#define MAX_SOCKADDR_LEN 256
51
52
53DISPATCH_HELPER_FUNCTIONS(sock, CFSocket)
54
7c97c3e0
A
55static 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);
59 int ret;
60 do {
61 memset(fdset, 0, sz);
62 FD_SET(fd, fdset);
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));
67 free(fdset);
68 return isSet;
69}
70
71static 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);
75 int ret;
76 do {
77 memset(fdset, 0, sz);
78 FD_SET(fd, fdset);
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));
83 free(fdset);
84 return isSet;
85}
86
cf7d2af9
A
87
88enum {
89 kCFSocketStateReady = 0,
90 kCFSocketStateInvalidating = 1,
91 kCFSocketStateInvalid = 2,
92 kCFSocketStateDeallocating = 3
93};
94
95struct __shared_blob {
96 dispatch_source_t _rdsrc;
97 dispatch_source_t _wrsrc;
98 CFRunLoopSourceRef _source;
99 CFSocketNativeHandle _socket;
100 uint8_t _closeFD;
101 uint8_t _refCnt;
102};
103
104struct __CFSocket {
105 CFRuntimeBase _base;
106 struct __shared_blob *_shared; /* non-NULL when valid, NULL when invalid */
107
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 */
114
115 uint8_t _error;
116
117 uint8_t _rsuspended:1;
118 uint8_t _wsuspended:1;
119 uint8_t _readable:1;
120 uint8_t _writeable:1;
7c97c3e0 121 uint8_t _unused:4;
cf7d2af9
A
122
123 uint8_t _reenableRead:1;
124 uint8_t _readDisabled:1;
7c97c3e0 125 uint8_t _reenableWrite:1;
cf7d2af9
A
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;
131
132 int32_t _runLoopCounter;
133
134 CFDataRef _address; /* immutable, once created */
135 CFDataRef _peerAddress; /* immutable, once created */
136 CFSocketCallBack _callout; /* immutable */
137 CFSocketContext _context; /* immutable */
138};
139
140
141CF_INLINE Boolean __CFSocketIsValid(CFSocketRef sock) {
142 return kCFSocketStateReady == sock->_state;
143}
144
145static 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);
150 }
151 if (NULL == contextDesc) {
152 contextDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFSocket context %p>"), sock->_context.info);
153 }
154 Dl_info info;
155 void *addr = sock->_callout;
156 const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???";
157 int avail = -1;
158 ioctl(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",
7c97c3e0 169 sock->_wantWrite ? "Yes" : "No", sock->_reenableWrite ? "Yes" : "No", sock->_writeDisabled ? "Yes" : "No",
cf7d2af9
A
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",
172 sock->_error, avail,
173 sock->_shared ? sock->_shared->_source : NULL, name, addr, contextDesc);
174 if (NULL != contextDesc) {
175 CFRelease(contextDesc);
176 }
177 return result;
178}
179
180static 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;
188 }
189 if (sock->_address) {
190 CFRelease(sock->_address);
191 sock->_address = NULL;
192 }
193}
194
195static CFTypeID __kCFSocketTypeID = _kCFRuntimeNotATypeID;
196
197static const CFRuntimeClass __CFSocketClass = {
198 0,
199 "CFSocket",
200 NULL, // init
201 NULL, // copy
202 __CFSocketDeallocate,
203 NULL, // equal
204 NULL, // hash
205 NULL, //
206 __CFSocketCopyDescription
207};
208
209static CFMutableArrayRef __CFAllSockets = NULL;
210
211CFTypeID CFSocketGetTypeID(void) {
212 if (_kCFRuntimeNotATypeID == __kCFSocketTypeID) {
213 __kCFSocketTypeID = _CFRuntimeRegisterClass(&__CFSocketClass);
214 __CFAllSockets = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
215 struct rlimit lim1;
216 int ret1 = getrlimit(RLIMIT_NOFILE, &lim1);
217 int mib[] = {CTL_KERN, KERN_MAXFILESPERPROC};
218 int maxfd = 0;
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
228 }
229 }
230 return __kCFSocketTypeID;
231}
232
233CFSocketRef CFSocketCreateWithNative(CFAllocatorRef allocator, CFSocketNativeHandle ufd, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context) {
234 CHECK_FOR_FORK_RET(NULL);
235
236 CFSocketGetTypeID(); // cause initialization if necessary
237
238 struct stat statbuf;
239 int ret = fstat(ufd, &statbuf);
240 if (ret < 0) ufd = INVALID_SOCKET;
241
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);
7c97c3e0 246 if (1 && !sane) {
cf7d2af9
A
247 CFLog(kCFLogLevelWarning, CFSTR("*** CFSocketCreateWithNative(): creating CFSocket with silly fd type (%07o) -- may or may not work"), type);
248 }
249 }
250
251 if (INVALID_SOCKET != ufd) {
252 Boolean canHandle = false;
253 int tmp_kq = kqueue();
254 if (0 <= tmp_kq) {
255 struct kevent ev[2];
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
260 close(tmp_kq);
261 }
7c97c3e0 262 if (1 && !canHandle) {
cf7d2af9
A
263 CFLog(kCFLogLevelWarning, CFSTR("*** CFSocketCreateWithNative(): creating CFSocket with unsupported fd type -- may or may not work"));
264 }
265 }
266
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) {
272 return NULL;
273 }
274 memory->_callout = callout;
275 memory->_state = kCFSocketStateInvalid;
276 return memory;
277 }
278
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) {
284 CFRetain(s);
285 sock = s;
286 return;
287 }
288 }
289
290 SInt32 size = sizeof(struct __CFSocket) - sizeof(CFRuntimeBase);
291 CFSocketRef memory = (CFSocketRef)_CFRuntimeCreateInstance(allocator, CFSocketGetTypeID(), size, NULL);
292 if (NULL == memory) {
293 return;
294 }
295
296 int socketType = 0;
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;
301 }
302
303 memory->_rsuspended = true;
304 memory->_wsuspended = true;
305 memory->_readable = false;
306 memory->_writeable = false;
307
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;
7c97c3e0 313 memory->_reenableWrite = false;
cf7d2af9
A
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;
321
322 memory->_error = 0;
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;
334 }
335
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;
344
345 if (memory->_wantReadType) {
346 dispatch_source_t dsrc = NULL;
347 if (sane) {
348 dsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, ufd, 0, __sockQueue());
349 } else {
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);
352 }
353 dispatch_block_t event_block = ^{
354 memory->_readable = true;
355 if (!memory->_rsuspended) {
356 dispatch_suspend(dsrc);
7c97c3e0 357// CFLog(5, CFSTR("suspend %p due to read event block"), memory);
cf7d2af9
A
358 memory->_rsuspended = true;
359 }
360 if (shared->_source) {
361 CFRunLoopSourceSignal(shared->_source);
362 _CFRunLoopSourceWakeUpRunLoops(shared->_source);
363 }
364 };
365 dispatch_block_t cancel_block = ^{
366 shared->_rdsrc = NULL;
367 shared->_refCnt--;
368 if (0 == shared->_refCnt) {
7c97c3e0
A
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);
374 close(nullfd);
375 close(shared->_socket);
376 }
cf7d2af9
A
377 free(shared);
378 }
379 dispatch_release(dsrc);
380 };
381 dispatch_source_set_event_handler(dsrc, event_block);
382 dispatch_source_set_cancel_handler(dsrc, cancel_block);
383 shared->_rdsrc = dsrc;
384 }
385 if (memory->_wantWrite || memory->_wantConnect) {
386 dispatch_source_t dsrc = NULL;
387 if (sane) {
388 dsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, ufd, 0, __sockQueue());
389 } else {
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);
392 }
393 dispatch_block_t event_block = ^{
394 memory->_writeable = true;
395 if (!memory->_wsuspended) {
396 dispatch_suspend(dsrc);
7c97c3e0 397// CFLog(5, CFSTR("suspend %p due to write event block"), memory);
cf7d2af9
A
398 memory->_wsuspended = true;
399 }
400 if (shared->_source) {
401 CFRunLoopSourceSignal(shared->_source);
402 _CFRunLoopSourceWakeUpRunLoops(shared->_source);
403 }
404 };
405 dispatch_block_t cancel_block = ^{
406 shared->_wrsrc = NULL;
407 shared->_refCnt--;
408 if (0 == shared->_refCnt) {
7c97c3e0
A
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);
414 close(nullfd);
415 close(shared->_socket);
416 }
cf7d2af9
A
417 free(shared);
418 }
419 dispatch_release(dsrc);
420 };
421 dispatch_source_set_event_handler(dsrc, event_block);
422 dispatch_source_set_cancel_handler(dsrc, cancel_block);
423 shared->_wrsrc = dsrc;
424 }
425
426 if (shared->_rdsrc) {
427 shared->_refCnt++;
428 }
429 if (shared->_wrsrc) {
430 shared->_refCnt++;
431 }
432
433 memory->_state = kCFSocketStateReady;
434 CFArrayAppendValue(__CFAllSockets, memory);
435 sock = memory;
436 });
437// CFLog(5, CFSTR("CFSocketCreateWithNative(): created socket %p with callbacks 0x%x"), sock, callBackTypes);
7c97c3e0
A
438 if (sock && !CFSocketIsValid(sock)) { // must do this outside lock to avoid deadlock
439 CFRelease(sock);
440 sock = NULL;
441 }
cf7d2af9
A
442 return sock;
443}
444
445CFSocketNativeHandle CFSocketGetNative(CFSocketRef sock) {
446 CHECK_FOR_FORK_RET(INVALID_SOCKET);
447 __CFGenericValidateType(sock, CFSocketGetTypeID());
448 return sock->_shared ? sock->_shared->_socket : INVALID_SOCKET;
449}
450
451void 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));
455}
456
457CFDataRef 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];
7c97c3e0 465 socklen_t namelen = sizeof(name);
cf7d2af9
A
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);
469 }
470 }
471 result = sock->_address ? (CFDataRef)CFRetain(sock->_address) : NULL;
472 });
cf7d2af9
A
473 return result;
474}
475
476CFDataRef 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];
7c97c3e0 484 socklen_t namelen = sizeof(name);
cf7d2af9
A
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);
488 }
489 }
490 result = sock->_peerAddress ? (CFDataRef)CFRetain(sock->_peerAddress) : NULL;
491 });
cf7d2af9
A
492 return result;
493}
494
495CFOptionFlags CFSocketGetSocketFlags(CFSocketRef sock) {
496 CHECK_FOR_FORK();
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
7c97c3e0 501 if (sock->_reenableWrite) flags |= kCFSocketAutomaticallyReenableWriteCallBack;
cf7d2af9
A
502 if (sock->_leaveErrors) flags |= kCFSocketLeaveErrors;
503 if (sock->_closeOnInvalidate) flags |= kCFSocketCloseOnInvalidate;
504 });
cf7d2af9
A
505 return flags;
506}
507
508void CFSocketSetSocketFlags(CFSocketRef sock, CFOptionFlags flags) {
509 CHECK_FOR_FORK();
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;
7c97c3e0 514 sock->_reenableWrite = (sock->_wantWrite && (flags & kCFSocketAutomaticallyReenableWriteCallBack)) ? true : false;
cf7d2af9
A
515 sock->_leaveErrors = (flags & kCFSocketLeaveErrors) ? true : false;
516 sock->_closeOnInvalidate = (flags & kCFSocketCloseOnInvalidate) ? true : false;
517 if (sock->_shared) sock->_shared->_closeFD = sock->_closeOnInvalidate;
518 });
519// CFLog(5, CFSTR("CFSocketSetSocketFlags(%p, 0x%x) done"), sock, flags);
520}
521
522void 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) {
7c97c3e0
A
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;
535 }
536 if (sock->_shared->_source) {
537 CFRunLoopSourceSignal(sock->_shared->_source);
538 _CFRunLoopSourceWakeUpRunLoops(sock->_shared->_source);
539 }
540 } else if (sock->_rsuspended && sock->_shared->_rdsrc) {
cf7d2af9
A
541 sock->_rsuspended = false;
542 dispatch_resume(sock->_shared->_rdsrc);
543 }
544 sock->_readDisabled = false;
545 }
546 if (sock->_wantWrite && (callBackTypes & kCFSocketWriteCallBack)) {
7c97c3e0
A
547 if (sockfd_is_writeable(sock->_shared->_socket)) {
548 sock->_writeable = true;
549 if (!sock->_wsuspended) {
550 dispatch_suspend(sock->_shared->_wrsrc);
551 sock->_wsuspended = true;
552 }
553 if (sock->_shared->_source) {
554 CFRunLoopSourceSignal(sock->_shared->_source);
555 _CFRunLoopSourceWakeUpRunLoops(sock->_shared->_source);
556 }
557 } else if (sock->_wsuspended && sock->_shared->_wrsrc) {
cf7d2af9
A
558 sock->_wsuspended = false;
559 dispatch_resume(sock->_shared->_wrsrc);
560 }
561 sock->_writeDisabled = false;
562 }
563 if (sock->_wantConnect && !sock->_connected && (callBackTypes & kCFSocketConnectCallBack)) {
7c97c3e0
A
564 if (sockfd_is_writeable(sock->_shared->_socket)) {
565 sock->_writeable = true;
566 if (!sock->_wsuspended) {
567 dispatch_suspend(sock->_shared->_wrsrc);
568 sock->_wsuspended = true;
569 }
570 if (sock->_shared->_source) {
571 CFRunLoopSourceSignal(sock->_shared->_source);
572 _CFRunLoopSourceWakeUpRunLoops(sock->_shared->_source);
573 }
574 } else if (sock->_wsuspended && sock->_shared->_wrsrc) {
cf7d2af9
A
575 sock->_wsuspended = false;
576 dispatch_resume(sock->_shared->_wrsrc);
577 }
578 sock->_connectDisabled = false;
579 }
580 });
581// CFLog(5, CFSTR("CFSocketEnableCallBacks(%p, 0x%x) done"), sock, callBackTypes);
582}
583
584void CFSocketDisableCallBacks(CFSocketRef sock, CFOptionFlags callBackTypes) {
585 CHECK_FOR_FORK_RET();
586 __CFGenericValidateType(sock, CFSocketGetTypeID());
587// CFLog(5, CFSTR("CFSocketDisableCallBacks(%p, 0x%x) starting"), sock, callBackTypes);
588 dispatch_sync(__sockQueue(), ^{
589 if (!__CFSocketIsValid(sock)) return;
590 if (sock->_wantReadType && (callBackTypes & 0x3) == sock->_wantReadType) {
591 if (!sock->_rsuspended && sock->_shared->_rdsrc) {
592 dispatch_suspend(sock->_shared->_rdsrc);
593 sock->_rsuspended = true;
594 }
595 sock->_readDisabled = true;
596 }
597 if (sock->_wantWrite && (callBackTypes & kCFSocketWriteCallBack)) {
598 if (!sock->_wsuspended && sock->_shared->_wrsrc) {
599 dispatch_suspend(sock->_shared->_wrsrc);
600 sock->_wsuspended = true;
601 }
602 sock->_writeDisabled = true;
603 }
604 if (sock->_wantConnect && !sock->_connected && (callBackTypes & kCFSocketConnectCallBack)) {
605 if (!sock->_wsuspended && sock->_shared->_wrsrc) {
606 dispatch_suspend(sock->_shared->_wrsrc);
607 sock->_wsuspended = true;
608 }
609 sock->_connectDisabled = true;
610 }
611 });
612// CFLog(5, CFSTR("CFSocketDisableCallBacks(%p, 0x%x) done"), sock, callBackTypes);
613}
614
615void CFSocketInvalidate(CFSocketRef sock) {
616 CHECK_FOR_FORK_RET();
617 __CFGenericValidateType(sock, CFSocketGetTypeID());
618 CFRetain(sock);
619// CFLog(5, CFSTR("CFSocketInvalidate(%p) starting"), sock);
620 __block CFRunLoopSourceRef source = NULL;
621 __block Boolean wasReady = false;
622 dispatch_sync(__sockQueue(), ^{
623 wasReady = (sock->_state == kCFSocketStateReady);
624 if (wasReady) {
625 sock->_state = kCFSocketStateInvalidating;
626 OSMemoryBarrier();
627 for (CFIndex idx = 0, cnt = CFArrayGetCount(__CFAllSockets); idx < cnt; idx++) {
628 CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(__CFAllSockets, idx);
629 if (s == sock) {
630 CFArrayRemoveValueAtIndex(__CFAllSockets, idx);
631 break;
632 }
633 }
634 if (sock->_shared->_rdsrc) {
635 dispatch_source_cancel(sock->_shared->_rdsrc);
636 if (sock->_rsuspended) {
637 sock->_rsuspended = false;
638 dispatch_resume(sock->_shared->_rdsrc);
639 }
640 }
641 if (sock->_shared->_wrsrc) {
642 dispatch_source_cancel(sock->_shared->_wrsrc);
643 if (sock->_wsuspended) {
644 sock->_wsuspended = false;
645 dispatch_resume(sock->_shared->_wrsrc);
646 }
647 }
648 source = sock->_shared->_source;
649 sock->_shared->_source = NULL;
650 sock->_shared->_refCnt--;
651 if (0 == sock->_shared->_refCnt) {
7c97c3e0
A
652 if (sock->_shared->_closeFD) {
653 // thoroughly stop anything else from using the fd
654 (void)shutdown(sock->_shared->_socket, SHUT_RDWR);
655 int nullfd = open("/dev/null", O_RDONLY);
656 dup2(nullfd, sock->_shared->_socket);
657 close(nullfd);
658 close(sock->_shared->_socket);
659 }
cf7d2af9
A
660 free(sock->_shared);
661 }
662 sock->_shared = NULL;
663 }
664 });
665 if (wasReady) {
666 if (NULL != source) {
667 CFRunLoopSourceInvalidate(source);
668 CFRelease(source);
669 }
670 void *info = sock->_context.info;
671 sock->_context.info = NULL;
672 if (sock->_context.release) {
673 sock->_context.release(info);
674 }
675 sock->_state = kCFSocketStateInvalid;
676 OSMemoryBarrier();
677 }
678// CFLog(5, CFSTR("CFSocketInvalidate(%p) done%s"), sock, wasReady ? " -- done on this thread" : "");
679 CFRelease(sock);
680}
681
682Boolean CFSocketIsValid(CFSocketRef sock) {
683 __CFGenericValidateType(sock, CFSocketGetTypeID());
7c97c3e0
A
684 if (!__CFSocketIsValid(sock)) return false;
685 struct stat statbuf;
686 int ret = sock->_shared ? fstat(sock->_shared->_socket, &statbuf) : -1;
687 if (ret < 0) {
688 CFSocketInvalidate(sock);
689 return false;
690 }
691 return true;
cf7d2af9
A
692}
693
694
695static void __CFSocketPerform(void *info) { // CFRunLoop should only call this on one thread at a time
696 CHECK_FOR_FORK_RET();
697 CFSocketRef sock = (CFSocketRef)info;
698
699// CFLog(5, CFSTR("__CFSocketPerform(%p) starting '%@'"), sock, sock);
700 __block Boolean doRead = false, doWrite = false, doConnect = false, isValid = false;
701 __block int fd = INVALID_SOCKET;
702 __block SInt32 errorCode = 0;
7c97c3e0
A
703 __block int new_fd = INVALID_SOCKET;
704 __block CFDataRef address = NULL;
705 __block CFMutableDataRef data = NULL;
cf7d2af9
A
706 dispatch_sync(__sockQueue(), ^{
707 isValid = __CFSocketIsValid(sock);
708 if (!isValid) return;
7c97c3e0 709 fd = sock->_shared->_socket;
cf7d2af9 710 doRead = sock->_readable && sock->_wantReadType && !sock->_readDisabled;
7c97c3e0
A
711 if (doRead) {
712 sock->_readable = false;
713 doRead = sockfd_is_readable(fd);
714// if (!doRead) CFLog(5, CFSTR("__CFSocketPerform(%p) socket is not actually readable"), sock);
715 }
cf7d2af9
A
716 doWrite = sock->_writeable && sock->_wantWrite && !sock->_writeDisabled;
717 doConnect = sock->_writeable && sock->_wantConnect && !sock->_connectDisabled && !sock->_connected;
7c97c3e0
A
718 if (doWrite || doConnect) {
719 sock->_writeable = false;
720 if (doWrite) doWrite = sockfd_is_writeable(fd);
721 if (doConnect) doConnect = sockfd_is_writeable(fd);
cf7d2af9 722 }
7c97c3e0 723 if (!sock->_leaveErrors && (doWrite || doConnect)) { // not on read, for whatever reason
cf7d2af9
A
724 int errorSize = sizeof(errorCode);
725 int ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&errorCode, (socklen_t *)&errorSize);
726 if (0 != ret) errorCode = 0;
727 sock->_error = errorCode;
728 }
729 sock->_connected = true;
7c97c3e0
A
730// CFLog(5, CFSTR("__CFSocketPerform(%p) doing %d %d %d"), sock, doRead, doWrite, doConnect);
731 if (doRead) {
732 switch (sock->_wantReadType) {
733 case kCFSocketReadCallBack:
734 break;
735 case kCFSocketAcceptCallBack: {
736 uint8_t name[MAX_SOCKADDR_LEN];
737 socklen_t namelen = sizeof(name);
738 new_fd = accept(fd, (struct sockaddr *)name, (socklen_t *)&namelen);
739 if (INVALID_SOCKET != new_fd) {
740 address = CFDataCreate(CFGetAllocator(sock), name, namelen);
741 }
742 break;
743 }
744 case kCFSocketDataCallBack: {
745 uint8_t name[MAX_SOCKADDR_LEN];
746 socklen_t namelen = sizeof(name);
747 int avail = 0;
748 int ret = ioctl(fd, FIONREAD, &avail);
749 if (ret < 0 || avail < 256) avail = 256;
750 if ((1 << 20) < avail) avail = (1 << 20);
751 data = CFDataCreateMutable(CFGetAllocator(sock), 0);
752 CFDataSetLength(data, avail);
753 ssize_t len = recvfrom(fd, CFDataGetMutableBytePtr(data), avail, 0, (struct sockaddr *)name, (socklen_t *)&namelen);
754 CFIndex datalen = (len < 0) ? 0 : len;
755 CFDataSetLength(data, datalen);
756 if (0 < namelen) {
757 address = CFDataCreate(CFGetAllocator(sock), name, namelen);
758 } else if (sock->_connOriented) {
759 // cannot call CFSocketCopyPeerAddress(), or deadlock
760 if (!sock->_peerAddress) {
761 uint8_t name[MAX_SOCKADDR_LEN];
762 socklen_t namelen = sizeof(name);
763 int ret = getpeername(sock->_shared->_socket, (struct sockaddr *)name, (socklen_t *)&namelen);
764 if (0 == ret && 0 < namelen) {
765 sock->_peerAddress = CFDataCreate(CFGetAllocator(sock), name, namelen);
766 }
767 }
768 address = sock->_peerAddress ? (CFDataRef)CFRetain(sock->_peerAddress) : NULL;
769 }
770 if (NULL == address) {
771 address = CFDataCreate(CFGetAllocator(sock), NULL, 0);
772 }
773 break;
774 }
775 }
776 }
777 if (sock->_reenableRead) {
778// CFLog(5, CFSTR("__CFSocketPerform(%p) reenabling read %d %p"), sock, sock->_rsuspended, sock->_shared->_rdsrc);
779 if (sock->_rsuspended && sock->_shared->_rdsrc) {
780 sock->_rsuspended = false;
781 dispatch_resume(sock->_shared->_rdsrc);
782 }
783 }
784 if (sock->_reenableWrite) {
785 if (sock->_wsuspended && sock->_shared->_wrsrc) {
786 sock->_wsuspended = false;
787 dispatch_resume(sock->_shared->_wrsrc);
788 }
789 }
cf7d2af9
A
790 });
791// CFLog(5, CFSTR("__CFSocketPerform(%p) isValid:%d, doRead:%d, doWrite:%d, doConnect:%d error:%d"), sock, isValid, doRead, doWrite, doConnect, errorCode);
7c97c3e0 792 if (!isValid || !(doConnect || doRead || doWrite)) return;
cf7d2af9
A
793
794 void *context_info = NULL;
795 void (*context_release)(const void *) = NULL;
796 if (sock->_context.retain) {
797 context_info = (void *)sock->_context.retain(sock->_context.info);
798 context_release = sock->_context.release;
799 } else {
800 context_info = sock->_context.info;
801 }
802
803 Boolean calledOut = false;
804 if (doConnect) {
cf7d2af9 805 if (sock->_callout) sock->_callout(sock, kCFSocketConnectCallBack, NULL, (0 != errorCode) ? &errorCode : NULL, context_info);
cf7d2af9
A
806 calledOut = true;
807 }
808 if (doRead && (!calledOut || __CFSocketIsValid(sock))) {
809 switch (sock->_wantReadType) {
810 case kCFSocketReadCallBack:
cf7d2af9 811 if (sock->_callout) sock->_callout(sock, kCFSocketReadCallBack, NULL, NULL, context_info);
cf7d2af9
A
812 calledOut = true;
813 break;
7c97c3e0 814 case kCFSocketAcceptCallBack:
cf7d2af9 815 if (INVALID_SOCKET != new_fd) {
cf7d2af9
A
816 if (sock->_callout) sock->_callout(sock, kCFSocketAcceptCallBack, address, &new_fd, context_info);
817 calledOut = true;
cf7d2af9
A
818 }
819 break;
7c97c3e0 820 case kCFSocketDataCallBack:
cf7d2af9
A
821 if (sock->_callout) sock->_callout(sock, kCFSocketDataCallBack, address, data, context_info);
822 calledOut = true;
cf7d2af9
A
823 break;
824 }
cf7d2af9
A
825 }
826 if (doWrite && (!calledOut || __CFSocketIsValid(sock))) {
827 if (0 == errorCode) {
cf7d2af9 828 if (sock->_callout) sock->_callout(sock, kCFSocketWriteCallBack, NULL, NULL, context_info);
cf7d2af9
A
829 calledOut = true;
830 }
831 }
cf7d2af9 832
7c97c3e0
A
833 if (data && 0 == CFDataGetLength(data)) CFSocketInvalidate(sock);
834 if (address) CFRelease(address);
835 if (data) CFRelease(data);
cf7d2af9
A
836 if (context_release) {
837 context_release(context_info);
838 }
7c97c3e0 839
cf7d2af9
A
840 CHECK_FOR_FORK_RET();
841// CFLog(5, CFSTR("__CFSocketPerform(%p) done"), sock);
842}
843
844static void __CFSocketSchedule(void *info, CFRunLoopRef rl, CFStringRef mode) {
845 CFSocketRef sock = (CFSocketRef)info;
846 int32_t newVal = OSAtomicIncrement32Barrier(&sock->_runLoopCounter);
847 if (1 == newVal) { // on a transition from 0->1, the old code forced all desired callbacks enabled
848 CFOptionFlags types = sock->_wantReadType | (sock->_wantWrite ? kCFSocketWriteCallBack : 0) | (sock->_wantConnect ? kCFSocketConnectCallBack : 0);
849 CFSocketEnableCallBacks(sock, types);
850 }
851 CFRunLoopWakeUp(rl);
852}
853
854static void __CFSocketCancel(void *info, CFRunLoopRef rl, CFStringRef mode) {
855 CFSocketRef sock = (CFSocketRef)info;
856 OSAtomicDecrement32Barrier(&sock->_runLoopCounter);
857 CFRunLoopWakeUp(rl);
858}
859
860CFRunLoopSourceRef CFSocketCreateRunLoopSource(CFAllocatorRef allocator, CFSocketRef sock, CFIndex order) {
861 CHECK_FOR_FORK_RET(NULL);
862 __CFGenericValidateType(sock, CFSocketGetTypeID());
7c97c3e0 863 if (!CFSocketIsValid(sock)) return NULL;
cf7d2af9
A
864 __block CFRunLoopSourceRef result = NULL;
865 dispatch_sync(__sockQueue(), ^{
866 if (!__CFSocketIsValid(sock)) return;
7c97c3e0
A
867 if (NULL != sock->_shared->_source && !CFRunLoopSourceIsValid(sock->_shared->_source)) {
868 CFRelease(sock->_shared->_source);
869 sock->_shared->_source = NULL;
870 }
cf7d2af9
A
871 if (NULL == sock->_shared->_source) {
872 CFRunLoopSourceContext context;
873 context.version = 0;
874 context.info = (void *)sock;
875 context.retain = (const void *(*)(const void *))CFRetain;
876 context.release = (void (*)(const void *))CFRelease;
877 context.copyDescription = (CFStringRef (*)(const void *))__CFSocketCopyDescription;
878 context.equal = NULL;
879 context.hash = NULL;
880 context.schedule = __CFSocketSchedule;
881 context.cancel = __CFSocketCancel;
882 context.perform = __CFSocketPerform;
883 sock->_shared->_source = CFRunLoopSourceCreate(allocator, order, (CFRunLoopSourceContext *)&context);
884 if (sock->_shared->_source) {
885 if (sock->_wantReadType) {
7c97c3e0
A
886 if (sockfd_is_readable(sock->_shared->_socket)) {
887 sock->_readable = true;
888 if (!sock->_rsuspended) {
889 dispatch_suspend(sock->_shared->_rdsrc);
890 sock->_rsuspended = true;
891 }
892 if (sock->_shared->_source) {
893 CFRunLoopSourceSignal(sock->_shared->_source);
894 _CFRunLoopSourceWakeUpRunLoops(sock->_shared->_source);
895 }
896 } else if (sock->_rsuspended && sock->_shared->_rdsrc) {
cf7d2af9
A
897 sock->_rsuspended = false;
898 dispatch_resume(sock->_shared->_rdsrc);
899 }
900 }
901 if (sock->_wantWrite || (sock->_wantConnect && !sock->_connected)) {
7c97c3e0
A
902 if (sockfd_is_writeable(sock->_shared->_socket)) {
903 sock->_writeable = true;
904 if (!sock->_wsuspended) {
905 dispatch_suspend(sock->_shared->_wrsrc);
906 sock->_wsuspended = true;
907 }
908 if (sock->_shared->_source) {
909 CFRunLoopSourceSignal(sock->_shared->_source);
910 _CFRunLoopSourceWakeUpRunLoops(sock->_shared->_source);
911 }
912 } else if (sock->_wsuspended && sock->_shared->_wrsrc) {
cf7d2af9
A
913 sock->_wsuspended = false;
914 dispatch_resume(sock->_shared->_wrsrc);
915 }
916 }
917 }
918 }
919 result = sock->_shared->_source ? (CFRunLoopSourceRef)CFRetain(sock->_shared->_source) : NULL;
920 });
921// CFLog(5, CFSTR("CFSocketCreateRunLoopSource(%p) => %p"), sock, result);
922 return result;
923}
924
925
926void __CFSocketSetSocketReadBufferAttrs(CFSocketRef s, CFTimeInterval timeout, CFIndex length) {
927}
928
929CFIndex __CFSocketRead(CFSocketRef s, UInt8* buffer, CFIndex length, int* error) {
930 *error = 0;
931 int ret = read(CFSocketGetNative(s), buffer, length);
932 if (ret < 0) {
933 *error = errno;
934 }
935 return ret;
936}
937
938Boolean __CFSocketGetBytesAvailable(CFSocketRef s, CFIndex* ctBytesAvailable) {
939 int bytesAvailable;
940 int ret = ioctl(CFSocketGetNative(s), FIONREAD, &bytesAvailable);
941 if (ret < 0) return false;
942 *ctBytesAvailable = (CFIndex)bytesAvailable;
943 return true;
944}
945
946
947#else /* not NEW_SOCKET */
948
bd5b749c 949
9ce05555
A
950#include <CoreFoundation/CFSocket.h>
951#include <sys/types.h>
952#include <math.h>
953#include <limits.h>
cf7d2af9
A
954#include <sys/resource.h>
955#include <sys/sysctl.h>
9ce05555
A
956#include <CoreFoundation/CFArray.h>
957#include <CoreFoundation/CFData.h>
958#include <CoreFoundation/CFDictionary.h>
959#include <CoreFoundation/CFRunLoop.h>
960#include <CoreFoundation/CFString.h>
961#include <CoreFoundation/CFPropertyList.h>
962#include "CFInternal.h"
9ce05555 963#include <libc.h>
bd5b749c 964#include <dlfcn.h>
9ce05555 965
d8925383
A
966// On Mach we use a v0 RunLoopSource to make client callbacks. That source is signalled by a
967// separate SocketManager thread who uses select() to watch the sockets' fds.
d8925383 968
9ce05555
A
969//#define LOG_CFSOCKET
970
9ce05555 971#define INVALID_SOCKET (CFSocketNativeHandle)(-1)
9ce05555 972
bd5b749c
A
973#define closesocket(a) close((a))
974#define ioctlsocket(a,b,c) ioctl((a),(b),(c))
975
976CF_INLINE int __CFSocketLastError(void) {
977 return thread_errno();
978}
979
980CF_INLINE CFIndex __CFSocketFdGetSize(CFDataRef fdSet) {
981 return NBBY * CFDataGetLength(fdSet);
982}
983
984CF_INLINE Boolean __CFSocketFdSet(CFSocketNativeHandle sock, CFMutableDataRef fdSet) {
985 /* returns true if a change occurred, false otherwise */
986 Boolean retval = false;
987 if (INVALID_SOCKET != sock && 0 <= sock) {
988 CFIndex numFds = NBBY * CFDataGetLength(fdSet);
989 fd_mask *fds_bits;
990 if (sock >= numFds) {
991 CFIndex oldSize = numFds / NFDBITS, newSize = (sock + NFDBITS) / NFDBITS, changeInBytes = (newSize - oldSize) * sizeof(fd_mask);
992 CFDataIncreaseLength(fdSet, changeInBytes);
993 fds_bits = (fd_mask *)CFDataGetMutableBytePtr(fdSet);
994 memset(fds_bits + oldSize, 0, changeInBytes);
995 } else {
996 fds_bits = (fd_mask *)CFDataGetMutableBytePtr(fdSet);
997 }
998 if (!FD_ISSET(sock, (fd_set *)fds_bits)) {
999 retval = true;
1000 FD_SET(sock, (fd_set *)fds_bits);
1001 }
1002 }
1003 return retval;
1004}
1005
1006
bd5b749c
A
1007#define MAX_SOCKADDR_LEN 256
1008#define MAX_DATA_SIZE 65535
1009#define MAX_CONNECTION_ORIENTED_DATA_SIZE 32768
1010
9ce05555
A
1011/* locks are to be acquired in the following order:
1012 (1) __CFAllSocketsLock
1013 (2) an individual CFSocket's lock
1014 (3) __CFActiveSocketsLock
1015*/
bd5b749c 1016static CFSpinLock_t __CFAllSocketsLock = CFSpinLockInit; /* controls __CFAllSockets */
9ce05555 1017static CFMutableDictionaryRef __CFAllSockets = NULL;
bd5b749c 1018static CFSpinLock_t __CFActiveSocketsLock = CFSpinLockInit; /* controls __CFRead/WriteSockets, __CFRead/WriteSocketsFds, __CFSocketManagerThread, and __CFSocketManagerIteration */
d8925383 1019static volatile UInt32 __CFSocketManagerIteration = 0;
9ce05555
A
1020static CFMutableArrayRef __CFWriteSockets = NULL;
1021static CFMutableArrayRef __CFReadSockets = NULL;
1022static CFMutableDataRef __CFWriteSocketsFds = NULL;
1023static CFMutableDataRef __CFReadSocketsFds = NULL;
d8925383 1024static CFDataRef zeroLengthData = NULL;
bd5b749c 1025static Boolean __CFReadSocketsTimeoutInvalid = true; /* rebuild the timeout value before calling select */
9ce05555 1026
d8925383 1027static CFSocketNativeHandle __CFWakeupSocketPair[2] = {INVALID_SOCKET, INVALID_SOCKET};
9ce05555
A
1028static void *__CFSocketManagerThread = NULL;
1029
d8925383 1030static void __CFSocketDoCallback(CFSocketRef s, CFDataRef data, CFDataRef address, CFSocketNativeHandle sock);
9ce05555
A
1031
1032struct __CFSocket {
1033 CFRuntimeBase _base;
d8925383
A
1034 struct {
1035 unsigned client:8; // flags set by client (reenable, CloseOnInvalidate)
1036 unsigned disabled:8; // flags marking disabled callbacks
1037 unsigned connected:1; // Are we connected yet? (also true for connectionless sockets)
1038 unsigned writableHint:1; // Did the polling the socket show it to be writable?
1039 unsigned closeSignaled:1; // Have we seen FD_CLOSE? (only used on Win32)
1040 unsigned unused:13;
1041 } _f;
9ce05555
A
1042 CFSpinLock_t _lock;
1043 CFSpinLock_t _writeLock;
1044 CFSocketNativeHandle _socket; /* immutable */
1045 SInt32 _socketType;
1046 SInt32 _errorCode;
1047 CFDataRef _address;
1048 CFDataRef _peerAddress;
1049 SInt32 _socketSetCount;
d8925383 1050 CFRunLoopSourceRef _source0; // v0 RLS, messaged from SocketMgr
9ce05555
A
1051 CFMutableArrayRef _runLoops;
1052 CFSocketCallBack _callout; /* immutable */
1053 CFSocketContext _context; /* immutable */
bd5b749c 1054 CFMutableArrayRef _dataQueue; // queues to pass data from SocketMgr thread
9ce05555 1055 CFMutableArrayRef _addressQueue;
bd5b749c
A
1056
1057 struct timeval _readBufferTimeout;
1058 CFMutableDataRef _readBuffer;
1059 CFIndex _bytesToBuffer; /* is length of _readBuffer */
1060 CFIndex _bytesToBufferPos; /* where the next _CFSocketRead starts from */
1061 CFIndex _bytesToBufferReadPos; /* Where the buffer will next be read into (always after _bytesToBufferPos, but less than _bytesToBuffer) */
1062 Boolean _atEOF;
1063 int _bufferedReadError;
1064
1065 CFMutableDataRef _leftoverBytes;
9ce05555
A
1066};
1067
1068/* Bit 6 in the base reserved bits is used for write-signalled state (mutable) */
1069/* Bit 5 in the base reserved bits is used for read-signalled state (mutable) */
1070/* Bit 4 in the base reserved bits is used for invalid state (mutable) */
1071/* Bits 0-3 in the base reserved bits are used for callback types (immutable) */
1072/* Of this, bits 0-1 are used for the read callback type. */
1073
1074CF_INLINE Boolean __CFSocketIsWriteSignalled(CFSocketRef s) {
bd5b749c 1075 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 6, 6);
9ce05555
A
1076}
1077
1078CF_INLINE void __CFSocketSetWriteSignalled(CFSocketRef s) {
bd5b749c 1079 __CFBitfieldSetValue(((CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 6, 6, 1);
9ce05555
A
1080}
1081
1082CF_INLINE void __CFSocketUnsetWriteSignalled(CFSocketRef s) {
bd5b749c 1083 __CFBitfieldSetValue(((CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 6, 6, 0);
9ce05555
A
1084}
1085
1086CF_INLINE Boolean __CFSocketIsReadSignalled(CFSocketRef s) {
bd5b749c 1087 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 5, 5);
9ce05555
A
1088}
1089
1090CF_INLINE void __CFSocketSetReadSignalled(CFSocketRef s) {
bd5b749c 1091 __CFBitfieldSetValue(((CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 5, 5, 1);
9ce05555
A
1092}
1093
1094CF_INLINE void __CFSocketUnsetReadSignalled(CFSocketRef s) {
bd5b749c 1095 __CFBitfieldSetValue(((CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 5, 5, 0);
9ce05555
A
1096}
1097
1098CF_INLINE Boolean __CFSocketIsValid(CFSocketRef s) {
bd5b749c 1099 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 4, 4);
9ce05555
A
1100}
1101
1102CF_INLINE void __CFSocketSetValid(CFSocketRef s) {
bd5b749c 1103 __CFBitfieldSetValue(((CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 4, 4, 1);
9ce05555
A
1104}
1105
1106CF_INLINE void __CFSocketUnsetValid(CFSocketRef s) {
bd5b749c 1107 __CFBitfieldSetValue(((CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 4, 4, 0);
9ce05555
A
1108}
1109
1110CF_INLINE uint8_t __CFSocketCallBackTypes(CFSocketRef s) {
bd5b749c 1111 return (uint8_t)__CFBitfieldGetValue(((const CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 3, 0);
9ce05555
A
1112}
1113
1114CF_INLINE uint8_t __CFSocketReadCallBackType(CFSocketRef s) {
bd5b749c 1115 return (uint8_t)__CFBitfieldGetValue(((const CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 1, 0);
9ce05555
A
1116}
1117
1118CF_INLINE void __CFSocketSetCallBackTypes(CFSocketRef s, uint8_t types) {
bd5b749c 1119 __CFBitfieldSetValue(((CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 3, 0, types & 0xF);
9ce05555
A
1120}
1121
1122CF_INLINE void __CFSocketLock(CFSocketRef s) {
1123 __CFSpinLock(&(s->_lock));
1124}
1125
1126CF_INLINE void __CFSocketUnlock(CFSocketRef s) {
1127 __CFSpinUnlock(&(s->_lock));
1128}
1129
9ce05555
A
1130CF_INLINE Boolean __CFSocketIsConnectionOriented(CFSocketRef s) {
1131 return (SOCK_STREAM == s->_socketType || SOCK_SEQPACKET == s->_socketType);
1132}
1133
d8925383
A
1134CF_INLINE Boolean __CFSocketIsScheduled(CFSocketRef s) {
1135 return (s->_socketSetCount > 0);
1136}
1137
9ce05555
A
1138CF_INLINE void __CFSocketEstablishAddress(CFSocketRef s) {
1139 /* socket should already be locked */
1140 uint8_t name[MAX_SOCKADDR_LEN];
1141 int namelen = sizeof(name);
bd5b749c 1142 if (__CFSocketIsValid(s) && NULL == s->_address && INVALID_SOCKET != s->_socket && 0 == getsockname(s->_socket, (struct sockaddr *)name, (socklen_t *)&namelen) && NULL != name && 0 < namelen) {
9ce05555
A
1143 s->_address = CFDataCreate(CFGetAllocator(s), name, namelen);
1144 }
1145}
1146
1147CF_INLINE void __CFSocketEstablishPeerAddress(CFSocketRef s) {
1148 /* socket should already be locked */
1149 uint8_t name[MAX_SOCKADDR_LEN];
1150 int namelen = sizeof(name);
bd5b749c 1151 if (__CFSocketIsValid(s) && NULL == s->_peerAddress && INVALID_SOCKET != s->_socket && 0 == getpeername(s->_socket, (struct sockaddr *)name, (socklen_t *)&namelen) && NULL != name && 0 < namelen) {
9ce05555
A
1152 s->_peerAddress = CFDataCreate(CFGetAllocator(s), name, namelen);
1153 }
1154}
1155
d8925383 1156static Boolean __CFNativeSocketIsValid(CFSocketNativeHandle sock) {
d8925383
A
1157 SInt32 flags = fcntl(sock, F_GETFL, 0);
1158 return !(0 > flags && EBADF == thread_errno());
9ce05555
A
1159}
1160
1161CF_INLINE Boolean __CFSocketFdClr(CFSocketNativeHandle sock, CFMutableDataRef fdSet) {
1162 /* returns true if a change occurred, false otherwise */
1163 Boolean retval = false;
1164 if (INVALID_SOCKET != sock && 0 <= sock) {
9ce05555
A
1165 CFIndex numFds = NBBY * CFDataGetLength(fdSet);
1166 fd_mask *fds_bits;
1167 if (sock < numFds) {
1168 fds_bits = (fd_mask *)CFDataGetMutableBytePtr(fdSet);
1169 if (FD_ISSET(sock, (fd_set *)fds_bits)) {
1170 retval = true;
1171 FD_CLR(sock, (fd_set *)fds_bits);
1172 }
1173 }
9ce05555
A
1174 }
1175 return retval;
1176}
1177
1178static SInt32 __CFSocketCreateWakeupSocketPair(void) {
9ce05555 1179 return socketpair(PF_LOCAL, SOCK_DGRAM, 0, __CFWakeupSocketPair);
d8925383
A
1180}
1181
d8925383 1182
d8925383 1183// Version 0 RunLoopSources set a mask in an FD set to control what socket activity we hear about.
7c97c3e0 1184// Changes to the master fs_sets occur via these 4 functions.
d8925383 1185CF_INLINE Boolean __CFSocketSetFDForRead(CFSocketRef s) {
f32021b4 1186 __CFReadSocketsTimeoutInvalid = true;
7c97c3e0
A
1187 Boolean b = __CFSocketFdSet(s->_socket, __CFReadSocketsFds);
1188 if (b && INVALID_SOCKET != __CFWakeupSocketPair[0]) {
1189 uint8_t c = 'r';
1190 send(__CFWakeupSocketPair[0], &c, sizeof(c), 0);
1191 }
1192 return b;
d8925383
A
1193}
1194
1195CF_INLINE Boolean __CFSocketClearFDForRead(CFSocketRef s) {
f32021b4 1196 __CFReadSocketsTimeoutInvalid = true;
7c97c3e0
A
1197 Boolean b = __CFSocketFdClr(s->_socket, __CFReadSocketsFds);
1198 if (b && INVALID_SOCKET != __CFWakeupSocketPair[0]) {
1199 uint8_t c = 's';
1200 send(__CFWakeupSocketPair[0], &c, sizeof(c), 0);
1201 }
1202 return b;
d8925383 1203}
d8925383
A
1204
1205CF_INLINE Boolean __CFSocketSetFDForWrite(CFSocketRef s) {
cf7d2af9 1206// CFLog(5, CFSTR("__CFSocketSetFDForWrite(%p)"), s);
7c97c3e0
A
1207 Boolean b = __CFSocketFdSet(s->_socket, __CFWriteSocketsFds);
1208 if (b && INVALID_SOCKET != __CFWakeupSocketPair[0]) {
1209 uint8_t c = 'w';
1210 send(__CFWakeupSocketPair[0], &c, sizeof(c), 0);
1211 }
1212 return b;
d8925383
A
1213}
1214
1215CF_INLINE Boolean __CFSocketClearFDForWrite(CFSocketRef s) {
cf7d2af9 1216// CFLog(5, CFSTR("__CFSocketClearFDForWrite(%p)"), s);
7c97c3e0
A
1217 Boolean b = __CFSocketFdClr(s->_socket, __CFWriteSocketsFds);
1218 if (b && INVALID_SOCKET != __CFWakeupSocketPair[0]) {
1219 uint8_t c = 'x';
1220 send(__CFWakeupSocketPair[0], &c, sizeof(c), 0);
1221 }
1222 return b;
d8925383
A
1223}
1224
d8925383
A
1225
1226// CFNetwork needs to call this, especially for Win32 to get WSAStartup
1227static void __CFSocketInitializeSockets(void) {
9ce05555
A
1228 __CFWriteSockets = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, NULL);
1229 __CFReadSockets = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, NULL);
1230 __CFWriteSocketsFds = CFDataCreateMutable(kCFAllocatorSystemDefault, 0);
1231 __CFReadSocketsFds = CFDataCreateMutable(kCFAllocatorSystemDefault, 0);
d8925383 1232 zeroLengthData = CFDataCreateMutable(kCFAllocatorSystemDefault, 0);
9ce05555 1233 if (0 > __CFSocketCreateWakeupSocketPair()) {
bd5b749c 1234 CFLog(kCFLogLevelWarning, CFSTR("*** Could not create wakeup socket pair for CFSocket!!!"));
9ce05555 1235 } else {
d8925383 1236 UInt32 yes = 1;
9ce05555
A
1237 /* wakeup sockets must be non-blocking */
1238 ioctlsocket(__CFWakeupSocketPair[0], FIONBIO, &yes);
1239 ioctlsocket(__CFWakeupSocketPair[1], FIONBIO, &yes);
1240 __CFSocketFdSet(__CFWakeupSocketPair[1], __CFReadSocketsFds);
1241 }
1242}
1243
7c97c3e0 1244static CFRunLoopRef __CFSocketCopyRunLoopToWakeUp(CFRunLoopSourceRef src, CFMutableArrayRef runLoops) {
9ce05555 1245 CFRunLoopRef rl = NULL;
7c97c3e0 1246 SInt32 idx, cnt = CFArrayGetCount(runLoops);
9ce05555 1247 if (0 < cnt) {
7c97c3e0 1248 rl = (CFRunLoopRef)CFArrayGetValueAtIndex(runLoops, 0);
9ce05555 1249 for (idx = 1; NULL != rl && idx < cnt; idx++) {
7c97c3e0 1250 CFRunLoopRef value = (CFRunLoopRef)CFArrayGetValueAtIndex(runLoops, idx);
9ce05555
A
1251 if (value != rl) rl = NULL;
1252 }
1253 if (NULL == rl) { /* more than one different rl, so we must pick one */
d8925383
A
1254 /* ideally, this would be a run loop which isn't also in a
1255 * signaled state for this or another source, but that's tricky;
1256 * we pick one that is running in an appropriate mode for this
1257 * source, and from those if possible one that is waiting; then
1258 * we move this run loop to the end of the list to scramble them
1259 * a bit, and always search from the front */
1260 Boolean foundIt = false, foundBackup = false;
1261 SInt32 foundIdx = 0;
1262 for (idx = 0; !foundIt && idx < cnt; idx++) {
7c97c3e0 1263 CFRunLoopRef value = (CFRunLoopRef)CFArrayGetValueAtIndex(runLoops, idx);
9ce05555 1264 CFStringRef currentMode = CFRunLoopCopyCurrentMode(value);
d8925383 1265 if (NULL != currentMode) {
7c97c3e0 1266 if (CFRunLoopContainsSource(value, src, currentMode)) {
d8925383
A
1267 if (CFRunLoopIsWaiting(value)) {
1268 foundIdx = idx;
1269 foundIt = true;
1270 } else if (!foundBackup) {
1271 foundIdx = idx;
1272 foundBackup = true;
1273 }
1274 }
9ce05555 1275 CFRelease(currentMode);
9ce05555 1276 }
9ce05555 1277 }
7c97c3e0 1278 rl = (CFRunLoopRef)CFArrayGetValueAtIndex(runLoops, foundIdx);
d8925383 1279 CFRetain(rl);
7c97c3e0
A
1280 CFArrayRemoveValueAtIndex(runLoops, foundIdx);
1281 CFArrayAppendValue(runLoops, rl);
d8925383
A
1282 } else {
1283 CFRetain(rl);
9ce05555
A
1284 }
1285 }
9ce05555
A
1286 return rl;
1287}
1288
d8925383
A
1289// If callBackNow, we immediately do client callbacks, else we have to signal a v0 RunLoopSource so the
1290// callbacks can happen in another thread.
1291static void __CFSocketHandleWrite(CFSocketRef s, Boolean callBackNow) {
9ce05555
A
1292 SInt32 errorCode = 0;
1293 int errorSize = sizeof(errorCode);
9ce05555
A
1294 CFOptionFlags writeCallBacksAvailable;
1295
1296 if (!CFSocketIsValid(s)) return;
bd5b749c 1297 if (0 != (s->_f.client & kCFSocketLeaveErrors) || 0 != getsockopt(s->_socket, SOL_SOCKET, SO_ERROR, (void *)&errorCode, (socklen_t *)&errorSize)) errorCode = 0; // cast for WinSock bad API
9ce05555 1298#if defined(LOG_CFSOCKET)
d8925383 1299 if (errorCode) fprintf(stdout, "error %ld on socket %d\n", errorCode, s->_socket);
f32021b4 1300#endif
9ce05555
A
1301 __CFSocketLock(s);
1302 writeCallBacksAvailable = __CFSocketCallBackTypes(s) & (kCFSocketWriteCallBack | kCFSocketConnectCallBack);
d8925383
A
1303 if ((s->_f.client & kCFSocketConnectCallBack) != 0) writeCallBacksAvailable &= ~kCFSocketConnectCallBack;
1304 if (!__CFSocketIsValid(s) || ((s->_f.disabled & writeCallBacksAvailable) == writeCallBacksAvailable)) {
9ce05555
A
1305 __CFSocketUnlock(s);
1306 return;
1307 }
1308 s->_errorCode = errorCode;
1309 __CFSocketSetWriteSignalled(s);
cf7d2af9 1310// CFLog(5, CFSTR("__CFSocketHandleWrite() signalling write on socket %p"), s);
9ce05555 1311#if defined(LOG_CFSOCKET)
d8925383 1312 fprintf(stdout, "write signaling source for socket %d\n", s->_socket);
f32021b4 1313#endif
d8925383
A
1314 if (callBackNow) {
1315 __CFSocketDoCallback(s, NULL, NULL, 0);
1316 } else {
d8925383 1317 CFRunLoopSourceSignal(s->_source0);
7c97c3e0
A
1318 CFMutableArrayRef runLoopsOrig = (CFMutableArrayRef)CFRetain(s->_runLoops);
1319 CFMutableArrayRef runLoopsCopy = CFArrayCreateMutableCopy(kCFAllocatorSystemDefault, 0, s->_runLoops);
1320 CFRunLoopSourceRef source0 = s->_source0;
1321 if (NULL != source0 && !CFRunLoopSourceIsValid(source0)) {
1322 source0 = NULL;
1323 }
1324 if (source0) CFRetain(source0);
d8925383 1325 __CFSocketUnlock(s);
7c97c3e0
A
1326 CFRunLoopRef rl = __CFSocketCopyRunLoopToWakeUp(source0, runLoopsCopy);
1327 if (source0) CFRelease(source0);
d8925383
A
1328 if (NULL != rl) {
1329 CFRunLoopWakeUp(rl);
1330 CFRelease(rl);
1331 }
7c97c3e0
A
1332 __CFSocketLock(s);
1333 if (runLoopsOrig == s->_runLoops) {
1334 s->_runLoops = runLoopsCopy;
1335 runLoopsCopy = NULL;
1336 CFRelease(runLoopsOrig);
1337 }
1338 __CFSocketUnlock(s);
1339 CFRelease(runLoopsOrig);
1340 if (runLoopsCopy) CFRelease(runLoopsCopy);
9ce05555
A
1341 }
1342}
1343
bd5b749c
A
1344static void __CFSocketHandleRead(CFSocketRef s, Boolean causedByTimeout)
1345{
d8925383
A
1346 CFDataRef data = NULL, address = NULL;
1347 CFSocketNativeHandle sock = INVALID_SOCKET;
9ce05555
A
1348 if (!CFSocketIsValid(s)) return;
1349 if (__CFSocketReadCallBackType(s) == kCFSocketDataCallBack) {
bd5b749c 1350 uint8_t bufferArray[MAX_CONNECTION_ORIENTED_DATA_SIZE], *buffer;
9ce05555
A
1351 uint8_t name[MAX_SOCKADDR_LEN];
1352 int namelen = sizeof(name);
bd5b749c
A
1353 SInt32 recvlen = 0;
1354 if (__CFSocketIsConnectionOriented(s)) {
1355 buffer = bufferArray;
1356 recvlen = recvfrom(s->_socket, buffer, MAX_CONNECTION_ORIENTED_DATA_SIZE, 0, (struct sockaddr *)name, (socklen_t *)&namelen);
1357 } else {
1358 buffer = malloc(MAX_DATA_SIZE);
1359 if (buffer) recvlen = recvfrom(s->_socket, buffer, MAX_DATA_SIZE, 0, (struct sockaddr *)name, (socklen_t *)&namelen);
1360 }
9ce05555 1361#if defined(LOG_CFSOCKET)
d8925383 1362 fprintf(stdout, "read %ld bytes on socket %d\n", recvlen, s->_socket);
f32021b4 1363#endif
9ce05555
A
1364 if (0 >= recvlen) {
1365 //??? should return error if <0
1366 /* zero-length data is the signal for perform to invalidate */
1367 data = CFRetain(zeroLengthData);
1368 } else {
1369 data = CFDataCreate(CFGetAllocator(s), buffer, recvlen);
1370 }
bd5b749c 1371 if (buffer && buffer != bufferArray) free(buffer);
9ce05555
A
1372 __CFSocketLock(s);
1373 if (!__CFSocketIsValid(s)) {
1374 CFRelease(data);
1375 __CFSocketUnlock(s);
1376 return;
1377 }
1378 __CFSocketSetReadSignalled(s);
1379 if (NULL != name && 0 < namelen) {
1380 //??? possible optimizations: uniquing; storing last value
1381 address = CFDataCreate(CFGetAllocator(s), name, namelen);
1382 } else if (__CFSocketIsConnectionOriented(s)) {
1383 if (NULL == s->_peerAddress) __CFSocketEstablishPeerAddress(s);
1384 if (NULL != s->_peerAddress) address = CFRetain(s->_peerAddress);
1385 }
1386 if (NULL == address) {
1387 address = CFRetain(zeroLengthData);
1388 }
1389 if (NULL == s->_dataQueue) {
1390 s->_dataQueue = CFArrayCreateMutable(CFGetAllocator(s), 0, &kCFTypeArrayCallBacks);
1391 }
1392 if (NULL == s->_addressQueue) {
1393 s->_addressQueue = CFArrayCreateMutable(CFGetAllocator(s), 0, &kCFTypeArrayCallBacks);
1394 }
1395 CFArrayAppendValue(s->_dataQueue, data);
1396 CFRelease(data);
1397 CFArrayAppendValue(s->_addressQueue, address);
1398 CFRelease(address);
d8925383
A
1399 if (0 < recvlen
1400 && (s->_f.client & kCFSocketDataCallBack) != 0 && (s->_f.disabled & kCFSocketDataCallBack) == 0
1401 && __CFSocketIsScheduled(s)
d8925383 1402 ) {
9ce05555
A
1403 __CFSpinLock(&__CFActiveSocketsLock);
1404 /* restore socket to fds */
d8925383 1405 __CFSocketSetFDForRead(s);
9ce05555
A
1406 __CFSpinUnlock(&__CFActiveSocketsLock);
1407 }
1408 } else if (__CFSocketReadCallBackType(s) == kCFSocketAcceptCallBack) {
1409 uint8_t name[MAX_SOCKADDR_LEN];
1410 int namelen = sizeof(name);
bd5b749c 1411 sock = accept(s->_socket, (struct sockaddr *)name, (socklen_t *)&namelen);
9ce05555
A
1412 if (INVALID_SOCKET == sock) {
1413 //??? should return error
1414 return;
1415 }
1416 if (NULL != name && 0 < namelen) {
1417 address = CFDataCreate(CFGetAllocator(s), name, namelen);
1418 } else {
1419 address = CFRetain(zeroLengthData);
1420 }
1421 __CFSocketLock(s);
1422 if (!__CFSocketIsValid(s)) {
1423 closesocket(sock);
1424 CFRelease(address);
1425 __CFSocketUnlock(s);
1426 return;
1427 }
1428 __CFSocketSetReadSignalled(s);
1429 if (NULL == s->_dataQueue) {
1430 s->_dataQueue = CFArrayCreateMutable(CFGetAllocator(s), 0, NULL);
1431 }
1432 if (NULL == s->_addressQueue) {
1433 s->_addressQueue = CFArrayCreateMutable(CFGetAllocator(s), 0, &kCFTypeArrayCallBacks);
1434 }
bd5b749c 1435 CFArrayAppendValue(s->_dataQueue, (void *)(uintptr_t)sock);
9ce05555
A
1436 CFArrayAppendValue(s->_addressQueue, address);
1437 CFRelease(address);
d8925383
A
1438 if ((s->_f.client & kCFSocketAcceptCallBack) != 0 && (s->_f.disabled & kCFSocketAcceptCallBack) == 0
1439 && __CFSocketIsScheduled(s)
d8925383 1440 ) {
9ce05555
A
1441 __CFSpinLock(&__CFActiveSocketsLock);
1442 /* restore socket to fds */
d8925383 1443 __CFSocketSetFDForRead(s);
9ce05555
A
1444 __CFSpinUnlock(&__CFActiveSocketsLock);
1445 }
1446 } else {
1447 __CFSocketLock(s);
d8925383 1448 if (!__CFSocketIsValid(s) || (s->_f.disabled & kCFSocketReadCallBack) != 0) {
9ce05555
A
1449 __CFSocketUnlock(s);
1450 return;
1451 }
bd5b749c
A
1452
1453 if (causedByTimeout) {
1454#if defined(LOG_CFSOCKET)
1455 fprintf(stdout, "TIMEOUT RECEIVED - WILL SIGNAL IMMEDIATELY TO FLUSH (%d buffered)\n", s->_bytesToBufferPos);
f32021b4 1456#endif
bd5b749c
A
1457 /* we've got a timeout, but no bytes read. Ignore the timeout. */
1458 if (s->_bytesToBufferPos == 0) {
1459#if defined(LOG_CFSOCKET)
1460 fprintf(stdout, "TIMEOUT - but no bytes, restoring to active set\n");
1461 fflush(stdout);
1462#endif
1463
1464 __CFSpinLock(&__CFActiveSocketsLock);
1465 /* restore socket to fds */
1466 __CFSocketSetFDForRead(s);
1467 __CFSpinUnlock(&__CFActiveSocketsLock);
1468 __CFSocketUnlock(s);
1469 return;
1470 }
1471 } else if (s->_bytesToBuffer != 0 && ! s->_atEOF) {
1472 UInt8* base;
1473 CFIndex ctRead;
1474 CFIndex ctRemaining = s->_bytesToBuffer - s->_bytesToBufferPos;
1475
1476 /* if our buffer has room, we go ahead and buffer */
1477 if (ctRemaining > 0) {
1478 base = CFDataGetMutableBytePtr(s->_readBuffer);
1479
1480 do {
1481 ctRead = read(CFSocketGetNative(s), &base[s->_bytesToBufferPos], ctRemaining);
1482 } while (ctRead == -1 && errno == EAGAIN);
1483
1484 switch (ctRead) {
1485 case -1:
1486 s->_bufferedReadError = errno;
1487 s->_atEOF = true;
1488#if defined(LOG_CFSOCKET)
1489 fprintf(stderr, "BUFFERED READ GOT ERROR %d\n", errno);
f32021b4 1490#endif
bd5b749c
A
1491 break;
1492
1493 case 0:
1494 #if defined(LOG_CFSOCKET)
1495 fprintf(stdout, "DONE READING (EOF) - GOING TO SIGNAL\n");
f32021b4 1496 #endif
bd5b749c
A
1497 s->_atEOF = true;
1498 break;
1499
1500 default:
1501 s->_bytesToBufferPos += ctRead;
1502 if (s->_bytesToBuffer != s->_bytesToBufferPos) {
1503 #if defined(LOG_CFSOCKET)
1504 fprintf(stdout, "READ %d - need %d MORE - GOING BACK FOR MORE\n", ctRead, s->_bytesToBuffer - s->_bytesToBufferPos);
f32021b4 1505 #endif
bd5b749c
A
1506 __CFSpinLock(&__CFActiveSocketsLock);
1507 /* restore socket to fds */
1508 __CFSocketSetFDForRead(s);
1509 __CFSpinUnlock(&__CFActiveSocketsLock);
1510 __CFSocketUnlock(s);
1511 return;
1512 } else {
1513 #if defined(LOG_CFSOCKET)
1514 fprintf(stdout, "DONE READING (read %d bytes) - GOING TO SIGNAL\n", ctRead);
f32021b4 1515 #endif
bd5b749c
A
1516 }
1517 }
1518 }
1519 }
1520
1521 __CFSocketSetReadSignalled(s);
9ce05555 1522 }
9ce05555 1523#if defined(LOG_CFSOCKET)
d8925383 1524 fprintf(stdout, "read signaling source for socket %d\n", s->_socket);
f32021b4 1525#endif
d8925383 1526 CFRunLoopSourceSignal(s->_source0);
7c97c3e0
A
1527 CFMutableArrayRef runLoopsOrig = (CFMutableArrayRef)CFRetain(s->_runLoops);
1528 CFMutableArrayRef runLoopsCopy = CFArrayCreateMutableCopy(kCFAllocatorSystemDefault, 0, s->_runLoops);
1529 CFRunLoopSourceRef source0 = s->_source0;
1530 if (NULL != source0 && !CFRunLoopSourceIsValid(source0)) {
1531 source0 = NULL;
1532 }
1533 if (source0) CFRetain(source0);
9ce05555 1534 __CFSocketUnlock(s);
7c97c3e0
A
1535 CFRunLoopRef rl = __CFSocketCopyRunLoopToWakeUp(source0, runLoopsCopy);
1536 if (source0) CFRelease(source0);
9ce05555
A
1537 if (NULL != rl) {
1538 CFRunLoopWakeUp(rl);
1539 CFRelease(rl);
1540 }
7c97c3e0
A
1541 __CFSocketLock(s);
1542 if (runLoopsOrig == s->_runLoops) {
1543 s->_runLoops = runLoopsCopy;
1544 runLoopsCopy = NULL;
1545 CFRelease(runLoopsOrig);
1546 }
1547 __CFSocketUnlock(s);
1548 CFRelease(runLoopsOrig);
1549 if (runLoopsCopy) CFRelease(runLoopsCopy);
bd5b749c
A
1550}
1551
1552static struct timeval* intervalToTimeval(CFTimeInterval timeout, struct timeval* tv)
1553{
1554 if (timeout == 0.0)
1555 timerclear(tv);
1556 else {
1557 tv->tv_sec = (0 >= timeout || INT_MAX <= timeout) ? INT_MAX : (int)(float)floor(timeout);
1558 tv->tv_usec = (int)((timeout - floor(timeout)) * 1.0E6);
1559 }
1560 return tv;
1561}
1562
1563/* note that this returns a pointer to the min value, which won't have changed during
1564 the dictionary apply, since we've got the active sockets lock held */
1565static void _calcMinTimeout_locked(const void* val, void* ctxt)
1566{
cf7d2af9
A
1567 CFSocketRef s = (CFSocketRef) val;
1568 struct timeval** minTime = (struct timeval**) ctxt;
1569 if (timerisset(&s->_readBufferTimeout) && (*minTime == NULL || timercmp(&s->_readBufferTimeout, *minTime, <)))
1570 *minTime = &s->_readBufferTimeout;
f32021b4
A
1571 else if (s->_leftoverBytes) {
1572 /* If there's anyone with leftover bytes, they'll need to be awoken immediately */
1573 static struct timeval sKickerTime = { 0, 0 };
1574 *minTime = &sKickerTime;
1575 }
bd5b749c
A
1576}
1577
f32021b4 1578void __CFSocketSetSocketReadBufferAttrs(CFSocketRef s, CFTimeInterval timeout, CFIndex length)
bd5b749c
A
1579{
1580 struct timeval timeoutVal;
cf7d2af9 1581
bd5b749c 1582 intervalToTimeval(timeout, &timeoutVal);
cf7d2af9
A
1583
1584 /* lock ordering is socket lock, activesocketslock */
1585 /* activesocketslock protects our timeout calculation */
bd5b749c 1586 __CFSocketLock(s);
cf7d2af9 1587 __CFSpinLock(&__CFActiveSocketsLock);
7c97c3e0 1588
cf7d2af9 1589 if (s->_bytesToBuffer != length) {
f32021b4
A
1590 CFIndex ctBuffer = s->_bytesToBufferPos - s->_bytesToBufferReadPos;
1591
1592 if (ctBuffer) {
cf7d2af9
A
1593 /* As originally envisaged, you were supposed to be sure to drain the buffer before
1594 * issuing another request on the socket. In practice, there seem to be times when we want to re-use
1595 * the stream (or perhaps, are on our way to closing it out) and this policy doesn't work so well.
1596 * So, if someone changes the buffer size while we have bytes already buffered, we put them
1597 * aside and use them to satisfy any subsequent reads.
1598 */
f32021b4
A
1599#if defined(LOG_CFSOCKET)
1600 __socketLog("%s(%d): WARNING: shouldn't set read buffer length while data (%d bytes) is still in the read buffer (leftover total %d)", __FUNCTION__, __LINE__, ctBuffer, s->_leftoverBytes? CFDataGetLength(s->_leftoverBytes) : 0);
bd5b749c 1601#endif
f32021b4 1602
cf7d2af9
A
1603 if (s->_leftoverBytes == NULL)
1604 s->_leftoverBytes = CFDataCreateMutable(CFGetAllocator(s), 0);
1605
1606 /* append the current buffered bytes over. We'll keep draining _leftoverBytes while we have them... */
f32021b4 1607 CFDataAppendBytes(s->_leftoverBytes, CFDataGetBytePtr(s->_readBuffer) + s->_bytesToBufferReadPos, ctBuffer);
cf7d2af9
A
1608 CFRelease(s->_readBuffer);
1609 s->_readBuffer = NULL;
1610
1611 s->_bytesToBuffer = 0;
1612 s->_bytesToBufferPos = 0;
1613 s->_bytesToBufferReadPos = 0;
1614 }
1615 if (length == 0) {
1616 s->_bytesToBuffer = 0;
1617 s->_bytesToBufferPos = 0;
1618 s->_bytesToBufferReadPos = 0;
1619 if (s->_readBuffer) {
1620 CFRelease(s->_readBuffer);
1621 s->_readBuffer = NULL;
1622 }
1623 // Zero length buffer, smash the timeout
1624 timeoutVal = (struct timeval) { 0, 0 };
1625 } else {
1626 /* if the buffer shrank, we can re-use the old one */
1627 if (length > s->_bytesToBuffer) {
1628 if (s->_readBuffer) {
1629 CFRelease(s->_readBuffer);
1630 s->_readBuffer = NULL;
1631 }
1632 }
1633
1634 s->_bytesToBuffer = length;
1635 s->_bytesToBufferPos = 0;
1636 s->_bytesToBufferReadPos = 0;
1637 if (s->_readBuffer == NULL) {
f32021b4 1638 s->_readBuffer = CFDataCreateMutable(kCFAllocatorSystemDefault, length);
cf7d2af9
A
1639 CFDataSetLength(s->_readBuffer, length);
1640 }
1641 }
1642 }
f32021b4
A
1643
1644 if (timercmp(&s->_readBufferTimeout, &timeoutVal, !=)) {
1645 s->_readBufferTimeout = timeoutVal;
1646 __CFReadSocketsTimeoutInvalid = true;
1647 }
1648
1649 __CFSpinUnlock(&__CFActiveSocketsLock);
cf7d2af9 1650 __CFSocketUnlock(s);
f32021b4
A
1651}
1652
bd5b749c
A
1653CFIndex __CFSocketRead(CFSocketRef s, UInt8* buffer, CFIndex length, int* error)
1654{
1655#if defined(LOG_CFSOCKET)
1656 fprintf(stdout, "READING BYTES FOR SOCKET %d (%d buffered, out of %d desired, eof = %d, err = %d)\n", s->_socket, s->_bytesToBufferPos, s->_bytesToBuffer, s->_atEOF, s->_bufferedReadError);
f32021b4 1657#endif
bd5b749c
A
1658
1659 CFIndex result = -1;
1660
1661 __CFSocketLock(s);
1662
1663 *error = 0;
1664
1665 /* Any leftover buffered bytes? */
1666 if (s->_leftoverBytes) {
1667 CFIndex ctBuffer = CFDataGetLength(s->_leftoverBytes);
1668#if defined(DEBUG)
cf7d2af9 1669 fprintf(stderr, "%s(%ld): WARNING: Draining %ld leftover bytes first\n\n", __FUNCTION__, (long)__LINE__, (long)ctBuffer);
bd5b749c
A
1670#endif
1671 if (ctBuffer > length)
1672 ctBuffer = length;
1673 memcpy(buffer, CFDataGetBytePtr(s->_leftoverBytes), ctBuffer);
1674 if (ctBuffer < CFDataGetLength(s->_leftoverBytes))
1675 CFDataReplaceBytes(s->_leftoverBytes, CFRangeMake(0, ctBuffer), NULL, 0);
1676 else {
1677 CFRelease(s->_leftoverBytes);
1678 s->_leftoverBytes = NULL;
1679 }
1680 result = ctBuffer;
1681 goto unlock;
1682 }
1683
1684 /* return whatever we've buffered */
1685 if (s->_bytesToBuffer != 0) {
1686 CFIndex ctBuffer = s->_bytesToBufferPos - s->_bytesToBufferReadPos;
1687 if (ctBuffer > 0) {
1688 /* drain our buffer first */
1689 if (ctBuffer > length)
1690 ctBuffer = length;
1691 memcpy(buffer, CFDataGetBytePtr(s->_readBuffer) + s->_bytesToBufferReadPos, ctBuffer);
1692 s->_bytesToBufferReadPos += ctBuffer;
1693 if (s->_bytesToBufferReadPos == s->_bytesToBufferPos) {
1694#if defined(LOG_CFSOCKET)
1695 fprintf(stdout, "DRAINED BUFFER - SHOULD START BUFFERING AGAIN!\n");
f32021b4 1696#endif
bd5b749c
A
1697 s->_bytesToBufferPos = 0;
1698 s->_bytesToBufferReadPos = 0;
1699 }
1700
1701#if defined(LOG_CFSOCKET)
1702 fprintf(stdout, "SLURPED %d BYTES FROM BUFFER %d LEFT TO READ!\n", ctBuffer, length);
f32021b4 1703#endif
bd5b749c
A
1704
1705 result = ctBuffer;
1706 goto unlock;
1707 }
1708 }
1709 /* nothing buffered, or no buffer selected */
1710
1711 /* Did we get an error on a previous read (or buffered read)? */
1712 if (s->_bufferedReadError != 0) {
1713#if defined(LOG_CFSOCKET)
1714 fprintf(stdout, "RETURNING ERROR %d\n", s->_bufferedReadError);
f32021b4 1715#endif
bd5b749c
A
1716 *error = s->_bufferedReadError;
1717 result = -1;
1718 goto unlock;
1719 }
1720
1721 /* nothing buffered, if we've hit eof, don't bother reading any more */
1722 if (s->_atEOF) {
1723#if defined(LOG_CFSOCKET)
1724 fprintf(stdout, "RETURNING EOF\n");
f32021b4 1725#endif
bd5b749c
A
1726 result = 0;
1727 goto unlock;
1728 }
1729
1730 /* normal read */
1731 result = read(CFSocketGetNative(s), buffer, length);
1732#if defined(LOG_CFSOCKET)
1733 fprintf(stdout, "READ %d bytes", result);
f32021b4 1734#endif
bd5b749c
A
1735
1736 if (result == 0) {
1737 /* note that we hit EOF */
1738 s->_atEOF = true;
1739 } else if (result < 0) {
1740 *error = errno;
1741
1742 /* if it wasn't EAGAIN, record it (although we shouldn't get called again) */
1743 if (*error != EAGAIN) {
1744 s->_bufferedReadError = *error;
1745 }
1746 }
1747
1748unlock:
1749 __CFSocketUnlock(s);
1750
1751 return result;
1752}
1753
1754Boolean __CFSocketGetBytesAvailable(CFSocketRef s, CFIndex* ctBytesAvailable)
1755{
1756 CFIndex ctBuffer = s->_bytesToBufferPos - s->_bytesToBufferReadPos;
1757 if (ctBuffer != 0) {
1758 *ctBytesAvailable = ctBuffer;
1759 return true;
1760 } else {
1761 int result;
f32021b4 1762#if DEPLOYMENT_TARGET_WINDOWS
bd5b749c
A
1763 int bytesAvailable, intLen = sizeof(bytesAvailable);
1764 result = getsockopt(CFSocketGetNative(s), SOL_SOCKET, SO_NREAD, &bytesAvailable, (void *)&intLen);
1765#else
1766 unsigned long bytesAvailable;
1767 result = ioctlsocket(CFSocketGetNative(s), FIONREAD, &bytesAvailable);
1768#endif
1769 if (result < 0)
1770 return false;
1771 *ctBytesAvailable = (CFIndex) bytesAvailable;
1772 return true;
1773 }
9ce05555
A
1774}
1775
d8925383
A
1776#if defined(LOG_CFSOCKET)
1777static void __CFSocketWriteSocketList(CFArrayRef sockets, CFDataRef fdSet, Boolean onlyIfSet) {
1778 fd_set *tempfds = (fd_set *)CFDataGetBytePtr(fdSet);
1779 SInt32 idx, cnt;
1780 for (idx = 0, cnt = CFArrayGetCount(sockets); idx < cnt; idx++) {
1781 CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(sockets, idx);
1782 if (FD_ISSET(s->_socket, tempfds)) {
1783 fprintf(stdout, "%d ", s->_socket);
1784 } else if (!onlyIfSet) {
1785 fprintf(stdout, "(%d) ", s->_socket);
1786 }
1787 }
1788}
f32021b4 1789#endif
d8925383
A
1790
1791#ifdef __GNUC__
1792__attribute__ ((noreturn)) // mostly interesting for shutting up a warning
bd5b749c 1793#endif /* __GNUC__ */
d8925383
A
1794static void __CFSocketManager(void * arg)
1795{
7c97c3e0
A
1796 pthread_setname_np("com.apple.CFSocket.private");
1797 if (objc_collectingEnabled()) objc_registerThreadWithCollector();
9ce05555 1798 SInt32 nrfds, maxnrfds, fdentries = 1;
d8925383 1799 SInt32 rfds, wfds;
d8925383 1800 fd_set *exceptfds = NULL;
9ce05555
A
1801 fd_set *writefds = (fd_set *)CFAllocatorAllocate(kCFAllocatorSystemDefault, fdentries * sizeof(fd_mask), 0);
1802 fd_set *readfds = (fd_set *)CFAllocatorAllocate(kCFAllocatorSystemDefault, fdentries * sizeof(fd_mask), 0);
9ce05555
A
1803 fd_set *tempfds;
1804 SInt32 idx, cnt;
1805 uint8_t buffer[256];
1806 CFMutableArrayRef selectedWriteSockets = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
1807 CFMutableArrayRef selectedReadSockets = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
bd5b749c 1808 CFIndex selectedWriteSocketsIndex = 0, selectedReadSocketsIndex = 0;
9ce05555 1809
cf7d2af9
A
1810 struct timeval tv;
1811 struct timeval* pTimeout = NULL;
1812 struct timeval timeBeforeSelect;
1813
9ce05555
A
1814 for (;;) {
1815 __CFSpinLock(&__CFActiveSocketsLock);
d8925383 1816 __CFSocketManagerIteration++;
9ce05555 1817#if defined(LOG_CFSOCKET)
d8925383
A
1818 fprintf(stdout, "socket manager iteration %lu looking at read sockets ", __CFSocketManagerIteration);
1819 __CFSocketWriteSocketList(__CFReadSockets, __CFReadSocketsFds, FALSE);
1820 if (0 < CFArrayGetCount(__CFWriteSockets)) {
1821 fprintf(stdout, " and write sockets ");
1822 __CFSocketWriteSocketList(__CFWriteSockets, __CFWriteSocketsFds, FALSE);
9ce05555 1823 }
d8925383 1824 fprintf(stdout, "\n");
f32021b4 1825#endif
d8925383
A
1826 rfds = __CFSocketFdGetSize(__CFReadSocketsFds);
1827 wfds = __CFSocketFdGetSize(__CFWriteSocketsFds);
1828 maxnrfds = __CFMax(rfds, wfds);
9ce05555
A
1829 if (maxnrfds > fdentries * (int)NFDBITS) {
1830 fdentries = (maxnrfds + NFDBITS - 1) / NFDBITS;
1831 writefds = (fd_set *)CFAllocatorReallocate(kCFAllocatorSystemDefault, writefds, fdentries * sizeof(fd_mask), 0);
1832 readfds = (fd_set *)CFAllocatorReallocate(kCFAllocatorSystemDefault, readfds, fdentries * sizeof(fd_mask), 0);
1833 }
1834 memset(writefds, 0, fdentries * sizeof(fd_mask));
d8925383
A
1835 memset(readfds, 0, fdentries * sizeof(fd_mask));
1836 CFDataGetBytes(__CFWriteSocketsFds, CFRangeMake(0, CFDataGetLength(__CFWriteSocketsFds)), (UInt8 *)writefds);
9ce05555 1837 CFDataGetBytes(__CFReadSocketsFds, CFRangeMake(0, CFDataGetLength(__CFReadSocketsFds)), (UInt8 *)readfds);
bd5b749c
A
1838
1839 if (__CFReadSocketsTimeoutInvalid) {
1840 struct timeval* minTimeout = NULL;
1841 __CFReadSocketsTimeoutInvalid = false;
d8925383 1842#if defined(LOG_CFSOCKET)
7c97c3e0 1843 fprintf(stdout, "Figuring out which sockets have timeouts...\n");
f32021b4 1844#endif
bd5b749c
A
1845 CFArrayApplyFunction(__CFReadSockets, CFRangeMake(0, CFArrayGetCount(__CFReadSockets)), _calcMinTimeout_locked, (void*) &minTimeout);
1846
1847 if (minTimeout == NULL) {
1848#if defined(LOG_CFSOCKET)
7c97c3e0 1849 fprintf(stdout, "No one wants a timeout!\n");
f32021b4 1850#endif
bd5b749c
A
1851 pTimeout = NULL;
1852 } else {
1853#if defined(LOG_CFSOCKET)
1854 fprintf(stdout, "timeout will be %d, %d!\n", minTimeout->tv_sec, minTimeout->tv_usec);
f32021b4 1855#endif
bd5b749c
A
1856 tv = *minTimeout;
1857 pTimeout = &tv;
1858 }
1859 }
1860
1861 if (pTimeout) {
1862#if defined(LOG_CFSOCKET)
1863 fprintf(stdout, "select will have a %d, %d timeout\n", pTimeout->tv_sec, pTimeout->tv_usec);
f32021b4 1864#endif
bd5b749c
A
1865 gettimeofday(&timeBeforeSelect, NULL);
1866 }
1867
1868 __CFSpinUnlock(&__CFActiveSocketsLock);
1869
1870 nrfds = select(maxnrfds, readfds, writefds, exceptfds, pTimeout);
1871
1872#if defined(LOG_CFSOCKET)
1873 fprintf(stdout, "socket manager woke from select, ret=%ld\n", nrfds);
f32021b4 1874#endif
bd5b749c
A
1875
1876 /*
1877 * select returned a timeout
1878 */
1879 if (0 == nrfds) {
1880 struct timeval timeAfterSelect;
1881 struct timeval deltaTime;
1882 gettimeofday(&timeAfterSelect, NULL);
1883 /* timeBeforeSelect becomes the delta */
1884 timersub(&timeAfterSelect, &timeBeforeSelect, &deltaTime);
1885
1886#if defined(LOG_CFSOCKET)
1887 fprintf(stdout, "Socket manager received timeout - kicking off expired reads (expired delta %d, %d)\n", deltaTime.tv_sec, deltaTime.tv_usec);
f32021b4 1888#endif
bd5b749c
A
1889
1890 __CFSpinLock(&__CFActiveSocketsLock);
1891
1892 tempfds = NULL;
1893 cnt = CFArrayGetCount(__CFReadSockets);
1894 for (idx = 0; idx < cnt; idx++) {
1895 CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(__CFReadSockets, idx);
f32021b4 1896 if (timerisset(&s->_readBufferTimeout) || s->_leftoverBytes) {
bd5b749c
A
1897 CFSocketNativeHandle sock = s->_socket;
1898 // We might have an new element in __CFReadSockets that we weren't listening to,
1899 // in which case we must be sure not to test a bit in the fdset that is
1900 // outside our mask size.
1901 Boolean sockInBounds = (0 <= sock && sock < maxnrfds);
1902 /* if this sockets timeout is less than or equal elapsed time, then signal it */
f32021b4 1903 if (INVALID_SOCKET != sock && sockInBounds) {
bd5b749c
A
1904#if defined(LOG_CFSOCKET)
1905 fprintf(stdout, "Expiring socket %d (delta %d, %d)\n", sock, s->_readBufferTimeout.tv_sec, s->_readBufferTimeout.tv_usec);
f32021b4 1906#endif
bd5b749c
A
1907 CFArraySetValueAtIndex(selectedReadSockets, selectedReadSocketsIndex, s);
1908 selectedReadSocketsIndex++;
1909 /* socket is removed from fds here, will be restored in read handling or in perform function */
1910 if (!tempfds) tempfds = (fd_set *)CFDataGetMutableBytePtr(__CFReadSocketsFds);
1911 FD_CLR(sock, tempfds);
1912 }
1913 }
1914 }
1915
1916 __CFSpinUnlock(&__CFActiveSocketsLock);
1917
1918 /* and below, we dispatch through the normal read dispatch mechanism */
1919 }
1920
1921 if (0 > nrfds) {
d8925383 1922 SInt32 selectError = __CFSocketLastError();
9ce05555 1923#if defined(LOG_CFSOCKET)
d8925383 1924 fprintf(stdout, "socket manager received error %ld from select\n", selectError);
f32021b4 1925#endif
9ce05555
A
1926 if (EBADF == selectError) {
1927 CFMutableArrayRef invalidSockets = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
1928 __CFSpinLock(&__CFActiveSocketsLock);
1929 cnt = CFArrayGetCount(__CFWriteSockets);
1930 for (idx = 0; idx < cnt; idx++) {
1931 CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(__CFWriteSockets, idx);
d8925383 1932 if (!__CFNativeSocketIsValid(s->_socket)) {
9ce05555 1933#if defined(LOG_CFSOCKET)
d8925383 1934 fprintf(stdout, "socket manager found write socket %d invalid\n", s->_socket);
f32021b4 1935#endif
9ce05555
A
1936 CFArrayAppendValue(invalidSockets, s);
1937 }
1938 }
1939 cnt = CFArrayGetCount(__CFReadSockets);
1940 for (idx = 0; idx < cnt; idx++) {
1941 CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(__CFReadSockets, idx);
d8925383 1942 if (!__CFNativeSocketIsValid(s->_socket)) {
9ce05555 1943#if defined(LOG_CFSOCKET)
d8925383 1944 fprintf(stdout, "socket manager found read socket %d invalid\n", s->_socket);
f32021b4 1945#endif
9ce05555
A
1946 CFArrayAppendValue(invalidSockets, s);
1947 }
1948 }
1949 __CFSpinUnlock(&__CFActiveSocketsLock);
1950
1951 cnt = CFArrayGetCount(invalidSockets);
1952 for (idx = 0; idx < cnt; idx++) {
bd5b749c 1953 CFSocketInvalidate(((CFSocketRef)CFArrayGetValueAtIndex(invalidSockets, idx)));
9ce05555
A
1954 }
1955 CFRelease(invalidSockets);
1956 }
1957 continue;
1958 }
1959 if (FD_ISSET(__CFWakeupSocketPair[1], readfds)) {
1960 recv(__CFWakeupSocketPair[1], buffer, sizeof(buffer), 0);
1961#if defined(LOG_CFSOCKET)
d8925383 1962 fprintf(stdout, "socket manager received %c on wakeup socket\n", buffer[0]);
f32021b4 1963#endif
9ce05555
A
1964 }
1965 __CFSpinLock(&__CFActiveSocketsLock);
1966 tempfds = NULL;
1967 cnt = CFArrayGetCount(__CFWriteSockets);
1968 for (idx = 0; idx < cnt; idx++) {
1969 CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(__CFWriteSockets, idx);
1970 CFSocketNativeHandle sock = s->_socket;
d8925383
A
1971 // We might have an new element in __CFWriteSockets that we weren't listening to,
1972 // in which case we must be sure not to test a bit in the fdset that is
1973 // outside our mask size.
1974 Boolean sockInBounds = (0 <= sock && sock < maxnrfds);
d8925383
A
1975 if (INVALID_SOCKET != sock && sockInBounds) {
1976 if (FD_ISSET(sock, writefds)) {
bd5b749c
A
1977 CFArraySetValueAtIndex(selectedWriteSockets, selectedWriteSocketsIndex, s);
1978 selectedWriteSocketsIndex++;
d8925383
A
1979 /* socket is removed from fds here, restored by CFSocketReschedule */
1980 if (!tempfds) tempfds = (fd_set *)CFDataGetMutableBytePtr(__CFWriteSocketsFds);
1981 FD_CLR(sock, tempfds);
cf7d2af9 1982// CFLog(5, CFSTR("Manager: cleared socket %p from write fds"), s);
d8925383 1983 }
d8925383 1984 }
9ce05555
A
1985 }
1986 tempfds = NULL;
1987 cnt = CFArrayGetCount(__CFReadSockets);
1988 for (idx = 0; idx < cnt; idx++) {
1989 CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(__CFReadSockets, idx);
1990 CFSocketNativeHandle sock = s->_socket;
d8925383
A
1991 // We might have an new element in __CFReadSockets that we weren't listening to,
1992 // in which case we must be sure not to test a bit in the fdset that is
1993 // outside our mask size.
1994 Boolean sockInBounds = (0 <= sock && sock < maxnrfds);
d8925383 1995 if (INVALID_SOCKET != sock && sockInBounds && FD_ISSET(sock, readfds)) {
bd5b749c
A
1996 CFArraySetValueAtIndex(selectedReadSockets, selectedReadSocketsIndex, s);
1997 selectedReadSocketsIndex++;
9ce05555
A
1998 /* socket is removed from fds here, will be restored in read handling or in perform function */
1999 if (!tempfds) tempfds = (fd_set *)CFDataGetMutableBytePtr(__CFReadSocketsFds);
2000 FD_CLR(sock, tempfds);
2001 }
2002 }
2003 __CFSpinUnlock(&__CFActiveSocketsLock);
2004
bd5b749c 2005 for (idx = 0; idx < selectedWriteSocketsIndex; idx++) {
9ce05555 2006 CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(selectedWriteSockets, idx);
bd5b749c 2007 if (kCFNull == (CFNullRef)s) continue;
9ce05555 2008#if defined(LOG_CFSOCKET)
d8925383 2009 fprintf(stdout, "socket manager signaling socket %d for write\n", s->_socket);
f32021b4 2010#endif
d8925383 2011 __CFSocketHandleWrite(s, FALSE);
bd5b749c 2012 CFArraySetValueAtIndex(selectedWriteSockets, idx, kCFNull);
9ce05555 2013 }
bd5b749c
A
2014 selectedWriteSocketsIndex = 0;
2015
2016 for (idx = 0; idx < selectedReadSocketsIndex; idx++) {
9ce05555 2017 CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(selectedReadSockets, idx);
bd5b749c 2018 if (kCFNull == (CFNullRef)s) continue;
9ce05555 2019#if defined(LOG_CFSOCKET)
d8925383 2020 fprintf(stdout, "socket manager signaling socket %d for read\n", s->_socket);
f32021b4 2021#endif
bd5b749c
A
2022 __CFSocketHandleRead(s, nrfds == 0);
2023 CFArraySetValueAtIndex(selectedReadSockets, idx, kCFNull);
9ce05555 2024 }
bd5b749c 2025 selectedReadSocketsIndex = 0;
9ce05555 2026 }
9ce05555
A
2027}
2028
2029static CFStringRef __CFSocketCopyDescription(CFTypeRef cf) {
2030 CFSocketRef s = (CFSocketRef)cf;
2031 CFMutableStringRef result;
bd5b749c
A
2032 CFStringRef contextDesc = NULL;
2033 void *contextInfo = NULL;
2034 CFStringRef (*contextCopyDescription)(const void *info) = NULL;
2035 result = CFStringCreateMutable(CFGetAllocator(s), 0);
2036 __CFSocketLock(s);
2037 void *addr = s->_callout;
2038 Dl_info info;
2039 const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???";
2040 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);
2041 contextInfo = s->_context.info;
2042 contextCopyDescription = s->_context.copyDescription;
9ce05555 2043 __CFSocketUnlock(s);
bd5b749c
A
2044 if (NULL != contextInfo && NULL != contextCopyDescription) {
2045 contextDesc = (CFStringRef)contextCopyDescription(contextInfo);
2046 }
2047 if (NULL == contextDesc) {
2048 contextDesc = CFStringCreateWithFormat(CFGetAllocator(s), NULL, CFSTR("<CFSocket context %p>"), contextInfo);
2049 }
2050 CFStringAppend(result, contextDesc);
2051 CFStringAppend(result, CFSTR("}"));
2052 CFRelease(contextDesc);
9ce05555
A
2053 return result;
2054}
2055
bd5b749c
A
2056static void __CFSocketDeallocate(CFTypeRef cf) {
2057 /* Since CFSockets are cached, we can only get here sometime after being invalidated */
2058 CFSocketRef s = (CFSocketRef)cf;
2059 if (NULL != s->_address) {
2060 CFRelease(s->_address);
2061 s->_address = NULL;
9ce05555 2062 }
bd5b749c
A
2063 if (NULL != s->_readBuffer) {
2064 CFRelease(s->_readBuffer);
2065 s->_readBuffer = NULL;
9ce05555 2066 }
bd5b749c
A
2067 if (NULL != s->_leftoverBytes) {
2068 CFRelease(s->_leftoverBytes);
2069 s->_leftoverBytes = NULL;
2070 }
2071 timerclear(&s->_readBufferTimeout);
2072 s->_bytesToBuffer = 0;
2073 s->_bytesToBufferPos = 0;
2074 s->_bytesToBufferReadPos = 0;
2075 s->_atEOF = true;
2076 s->_bufferedReadError = 0;
9ce05555
A
2077}
2078
cf7d2af9
A
2079static CFTypeID __kCFSocketTypeID = _kCFRuntimeNotATypeID;
2080
bd5b749c
A
2081static const CFRuntimeClass __CFSocketClass = {
2082 0,
2083 "CFSocket",
2084 NULL, // init
2085 NULL, // copy
2086 __CFSocketDeallocate,
2087 NULL, // equal
2088 NULL, // hash
2089 NULL, //
2090 __CFSocketCopyDescription
2091};
2092
bd5b749c 2093CFTypeID CFSocketGetTypeID(void) {
cf7d2af9
A
2094 if (_kCFRuntimeNotATypeID == __kCFSocketTypeID) {
2095 __kCFSocketTypeID = _CFRuntimeRegisterClass(&__CFSocketClass);
2096 struct rlimit lim1;
2097 int ret1 = getrlimit(RLIMIT_NOFILE, &lim1);
2098 int mib[] = {CTL_KERN, KERN_MAXFILESPERPROC};
2099 int maxfd = 0;
2100 size_t len = sizeof(int);
2101 int ret0 = sysctl(mib, 2, &maxfd, &len, NULL, 0);
2102 if (0 == ret0 && 0 == ret1 && lim1.rlim_max < maxfd) maxfd = lim1.rlim_max;
2103 if (0 == ret1 && lim1.rlim_cur < maxfd) {
2104 struct rlimit lim2 = lim1;
2105 lim2.rlim_cur += 2304;
2106 if (maxfd < lim2.rlim_cur) lim2.rlim_cur = maxfd;
2107 setrlimit(RLIMIT_NOFILE, &lim2);
2108 // we try, but do not go to extraordinary measures
2109 }
2110 }
bd5b749c
A
2111 return __kCFSocketTypeID;
2112}
f32021b4 2113
bd5b749c
A
2114static CFSocketRef _CFSocketCreateWithNative(CFAllocatorRef allocator, CFSocketNativeHandle sock, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context, Boolean useExistingInstance) {
2115 CHECK_FOR_FORK();
9ce05555
A
2116 CFSocketRef memory;
2117 int typeSize = sizeof(memory->_socketType);
2118 __CFSpinLock(&__CFActiveSocketsLock);
2119 if (NULL == __CFReadSockets) __CFSocketInitializeSockets();
2120 __CFSpinUnlock(&__CFActiveSocketsLock);
2121 __CFSpinLock(&__CFAllSocketsLock);
2122 if (NULL == __CFAllSockets) {
2123 __CFAllSockets = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
2124 }
bd5b749c
A
2125 if (INVALID_SOCKET != sock && CFDictionaryGetValueIfPresent(__CFAllSockets, (void *)(uintptr_t)sock, (const void **)&memory)) {
2126 if (useExistingInstance) {
2127 __CFSpinUnlock(&__CFAllSocketsLock);
2128 CFRetain(memory);
2129 return memory;
2130 } else {
2131#if defined(LOG_CFSOCKET)
2132 fprintf(stdout, "useExistingInstance is FALSE, removing existing instance %d from __CFAllSockets\n", (int)memory);
f32021b4 2133#endif
bd5b749c
A
2134 __CFSpinUnlock(&__CFAllSocketsLock);
2135 CFSocketInvalidate(memory);
2136 __CFSpinLock(&__CFAllSocketsLock);
2137 }
9ce05555 2138 }
cf7d2af9 2139 memory = (CFSocketRef)_CFRuntimeCreateInstance(allocator, CFSocketGetTypeID(), sizeof(struct __CFSocket) - sizeof(CFRuntimeBase), NULL);
9ce05555
A
2140 if (NULL == memory) {
2141 __CFSpinUnlock(&__CFAllSocketsLock);
2142 return NULL;
2143 }
2144 __CFSocketSetCallBackTypes(memory, callBackTypes);
2145 if (INVALID_SOCKET != sock) __CFSocketSetValid(memory);
2146 __CFSocketUnsetWriteSignalled(memory);
2147 __CFSocketUnsetReadSignalled(memory);
d8925383
A
2148 memory->_f.client = ((callBackTypes & (~kCFSocketConnectCallBack)) & (~kCFSocketWriteCallBack)) | kCFSocketCloseOnInvalidate;
2149 memory->_f.disabled = 0;
2150 memory->_f.connected = FALSE;
2151 memory->_f.writableHint = FALSE;
2152 memory->_f.closeSignaled = FALSE;
bd5b749c
A
2153 memory->_lock = CFSpinLockInit;
2154 memory->_writeLock = CFSpinLockInit;
9ce05555 2155 memory->_socket = sock;
bd5b749c 2156 if (INVALID_SOCKET == sock || 0 != getsockopt(sock, SOL_SOCKET, SO_TYPE, (void *)&(memory->_socketType), (socklen_t *)&typeSize)) memory->_socketType = 0; // cast for WinSock bad API
9ce05555
A
2157 memory->_errorCode = 0;
2158 memory->_address = NULL;
2159 memory->_peerAddress = NULL;
2160 memory->_socketSetCount = 0;
d8925383 2161 memory->_source0 = NULL;
9ce05555 2162 if (INVALID_SOCKET != sock) {
7c97c3e0 2163 memory->_runLoops = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, NULL);
9ce05555
A
2164 } else {
2165 memory->_runLoops = NULL;
2166 }
2167 memory->_callout = callout;
2168 memory->_dataQueue = NULL;
2169 memory->_addressQueue = NULL;
9ce05555
A
2170 memory->_context.info = 0;
2171 memory->_context.retain = 0;
2172 memory->_context.release = 0;
2173 memory->_context.copyDescription = 0;
bd5b749c 2174 timerclear(&memory->_readBufferTimeout);
cf7d2af9
A
2175 memory->_readBuffer = NULL;
2176 memory->_bytesToBuffer = 0;
2177 memory->_bytesToBufferPos = 0;
2178 memory->_bytesToBufferReadPos = 0;
2179 memory->_atEOF = false;
2180 memory->_bufferedReadError = 0;
2181 memory->_leftoverBytes = NULL;
2182
bd5b749c 2183 if (INVALID_SOCKET != sock) CFDictionaryAddValue(__CFAllSockets, (void *)(uintptr_t)sock, memory);
7c97c3e0 2184 if (NULL == __CFSocketManagerThread) __CFSocketManagerThread = __CFStartSimpleThread(__CFSocketManager, 0);
9ce05555
A
2185 __CFSpinUnlock(&__CFAllSocketsLock);
2186 if (NULL != context) {
2187 void *contextInfo = context->retain ? (void *)context->retain(context->info) : context->info;
2188 __CFSocketLock(memory);
2189 memory->_context.retain = context->retain;
2190 memory->_context.release = context->release;
2191 memory->_context.copyDescription = context->copyDescription;
2192 memory->_context.info = contextInfo;
2193 __CFSocketUnlock(memory);
2194 }
cf7d2af9 2195// CFLog(5, CFSTR("CFSocketCreateWithNative(): created socket %p with callbacks 0x%x"), memory, callBackTypes);
9ce05555
A
2196 return memory;
2197}
2198
bd5b749c
A
2199CFSocketRef CFSocketCreateWithNative(CFAllocatorRef allocator, CFSocketNativeHandle sock, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context) {
2200 return _CFSocketCreateWithNative(allocator, sock, callBackTypes, callout, context, TRUE);
9ce05555
A
2201}
2202
bd5b749c 2203void CFSocketInvalidate(CFSocketRef s) {
cf7d2af9 2204// CFLog(5, CFSTR("CFSocketInvalidate(%p) starting"), s);
bd5b749c 2205 CHECK_FOR_FORK();
d8925383 2206 UInt32 previousSocketManagerIteration;
cf7d2af9 2207 __CFGenericValidateType(s, CFSocketGetTypeID());
d8925383 2208#if defined(LOG_CFSOCKET)
bd5b749c 2209 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);
f32021b4 2210#endif
9ce05555
A
2211 CFRetain(s);
2212 __CFSpinLock(&__CFAllSocketsLock);
2213 __CFSocketLock(s);
2214 if (__CFSocketIsValid(s)) {
2215 SInt32 idx;
d8925383 2216 CFRunLoopSourceRef source0;
9ce05555
A
2217 void *contextInfo = NULL;
2218 void (*contextRelease)(const void *info) = NULL;
2219 __CFSocketUnsetValid(s);
2220 __CFSocketUnsetWriteSignalled(s);
2221 __CFSocketUnsetReadSignalled(s);
2222 __CFSpinLock(&__CFActiveSocketsLock);
9ce05555
A
2223 idx = CFArrayGetFirstIndexOfValue(__CFWriteSockets, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets)), s);
2224 if (0 <= idx) {
2225 CFArrayRemoveValueAtIndex(__CFWriteSockets, idx);
d8925383 2226 __CFSocketClearFDForWrite(s);
9ce05555 2227 }
d8925383 2228 // No need to clear FD's for V1 sources, since we'll just throw the whole event away
9ce05555
A
2229 idx = CFArrayGetFirstIndexOfValue(__CFReadSockets, CFRangeMake(0, CFArrayGetCount(__CFReadSockets)), s);
2230 if (0 <= idx) {
2231 CFArrayRemoveValueAtIndex(__CFReadSockets, idx);
d8925383 2232 __CFSocketClearFDForRead(s);
9ce05555 2233 }
d8925383 2234 previousSocketManagerIteration = __CFSocketManagerIteration;
9ce05555 2235 __CFSpinUnlock(&__CFActiveSocketsLock);
bd5b749c 2236 CFDictionaryRemoveValue(__CFAllSockets, (void *)(uintptr_t)(s->_socket));
d8925383 2237 if ((s->_f.client & kCFSocketCloseOnInvalidate) != 0) closesocket(s->_socket);
9ce05555
A
2238 s->_socket = INVALID_SOCKET;
2239 if (NULL != s->_peerAddress) {
2240 CFRelease(s->_peerAddress);
2241 s->_peerAddress = NULL;
2242 }
2243 if (NULL != s->_dataQueue) {
2244 CFRelease(s->_dataQueue);
2245 s->_dataQueue = NULL;
2246 }
2247 if (NULL != s->_addressQueue) {
2248 CFRelease(s->_addressQueue);
2249 s->_addressQueue = NULL;
2250 }
2251 s->_socketSetCount = 0;
2252 for (idx = CFArrayGetCount(s->_runLoops); idx--;) {
2253 CFRunLoopWakeUp((CFRunLoopRef)CFArrayGetValueAtIndex(s->_runLoops, idx));
2254 }
2255 CFRelease(s->_runLoops);
2256 s->_runLoops = NULL;
d8925383
A
2257 source0 = s->_source0;
2258 s->_source0 = NULL;
9ce05555
A
2259 contextInfo = s->_context.info;
2260 contextRelease = s->_context.release;
2261 s->_context.info = 0;
2262 s->_context.retain = 0;
2263 s->_context.release = 0;
2264 s->_context.copyDescription = 0;
2265 __CFSocketUnlock(s);
2266 if (NULL != contextRelease) {
2267 contextRelease(contextInfo);
2268 }
d8925383
A
2269 if (NULL != source0) {
2270 CFRunLoopSourceInvalidate(source0);
2271 CFRelease(source0);
2272 }
9ce05555
A
2273 } else {
2274 __CFSocketUnlock(s);
2275 }
2276 __CFSpinUnlock(&__CFAllSocketsLock);
2277 CFRelease(s);
cf7d2af9 2278// CFLog(5, CFSTR("CFSocketInvalidate(%p) done"), s);
9ce05555
A
2279}
2280
2281Boolean CFSocketIsValid(CFSocketRef s) {
bd5b749c 2282 CHECK_FOR_FORK();
cf7d2af9 2283 __CFGenericValidateType(s, CFSocketGetTypeID());
9ce05555
A
2284 return __CFSocketIsValid(s);
2285}
2286
2287CFSocketNativeHandle CFSocketGetNative(CFSocketRef s) {
bd5b749c 2288 CHECK_FOR_FORK();
cf7d2af9 2289 __CFGenericValidateType(s, CFSocketGetTypeID());
9ce05555
A
2290 return s->_socket;
2291}
2292
2293CFDataRef CFSocketCopyAddress(CFSocketRef s) {
bd5b749c 2294 CHECK_FOR_FORK();
9ce05555 2295 CFDataRef result = NULL;
cf7d2af9 2296 __CFGenericValidateType(s, CFSocketGetTypeID());
9ce05555
A
2297 __CFSocketLock(s);
2298 __CFSocketEstablishAddress(s);
2299 if (NULL != s->_address) {
2300 result = CFRetain(s->_address);
2301 }
2302 __CFSocketUnlock(s);
cf7d2af9 2303// CFLog(5, CFSTR("CFSocketCopyAddress(): created socket %p address %@"), s, result);
9ce05555
A
2304 return result;
2305}
2306
2307CFDataRef CFSocketCopyPeerAddress(CFSocketRef s) {
bd5b749c 2308 CHECK_FOR_FORK();
9ce05555 2309 CFDataRef result = NULL;
cf7d2af9 2310 __CFGenericValidateType(s, CFSocketGetTypeID());
9ce05555
A
2311 __CFSocketLock(s);
2312 __CFSocketEstablishPeerAddress(s);
2313 if (NULL != s->_peerAddress) {
2314 result = CFRetain(s->_peerAddress);
2315 }
2316 __CFSocketUnlock(s);
cf7d2af9 2317// CFLog(5, CFSTR("CFSocketCopyAddress(): created socket %p peer address %@"), s, result);
9ce05555
A
2318 return result;
2319}
2320
2321void CFSocketGetContext(CFSocketRef s, CFSocketContext *context) {
bd5b749c 2322 CHECK_FOR_FORK();
cf7d2af9 2323 __CFGenericValidateType(s, CFSocketGetTypeID());
9ce05555
A
2324 CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__);
2325 *context = s->_context;
2326}
2327
9ce05555 2328CFOptionFlags CFSocketGetSocketFlags(CFSocketRef s) {
bd5b749c 2329 CHECK_FOR_FORK();
cf7d2af9 2330 __CFGenericValidateType(s, CFSocketGetTypeID());
d8925383 2331 return s->_f.client;
9ce05555
A
2332}
2333
2334void CFSocketSetSocketFlags(CFSocketRef s, CFOptionFlags flags) {
bd5b749c 2335 CHECK_FOR_FORK();
cf7d2af9 2336 __CFGenericValidateType(s, CFSocketGetTypeID());
9ce05555 2337 __CFSocketLock(s);
9ce05555 2338#if defined(LOG_CFSOCKET)
d8925383 2339 fprintf(stdout, "setting flags for socket %d, from 0x%x to 0x%lx\n", s->_socket, s->_f.client, flags);
f32021b4 2340#endif
d8925383 2341 s->_f.client = flags;
9ce05555 2342 __CFSocketUnlock(s);
cf7d2af9 2343// CFLog(5, CFSTR("CFSocketSetSocketFlags(%p, 0x%x)"), s, flags);
9ce05555
A
2344}
2345
2346void CFSocketDisableCallBacks(CFSocketRef s, CFOptionFlags callBackTypes) {
bd5b749c 2347 CHECK_FOR_FORK();
9ce05555 2348 Boolean wakeup = false;
d8925383 2349 uint8_t readCallBackType;
cf7d2af9 2350 __CFGenericValidateType(s, CFSocketGetTypeID());
9ce05555 2351 __CFSocketLock(s);
d8925383 2352 if (__CFSocketIsValid(s) && __CFSocketIsScheduled(s)) {
9ce05555
A
2353 callBackTypes &= __CFSocketCallBackTypes(s);
2354 readCallBackType = __CFSocketReadCallBackType(s);
d8925383 2355 s->_f.disabled |= callBackTypes;
9ce05555 2356#if defined(LOG_CFSOCKET)
d8925383 2357 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);
f32021b4 2358#endif
9ce05555 2359 __CFSpinLock(&__CFActiveSocketsLock);
d8925383
A
2360 if ((readCallBackType == kCFSocketAcceptCallBack) || !__CFSocketIsConnectionOriented(s)) s->_f.connected = TRUE;
2361 if (((callBackTypes & kCFSocketWriteCallBack) != 0) || (((callBackTypes & kCFSocketConnectCallBack) != 0) && !s->_f.connected)) {
2362 if (__CFSocketClearFDForWrite(s)) {
9ce05555
A
2363 // do not wake up the socket manager thread if all relevant write callbacks are disabled
2364 CFOptionFlags writeCallBacksAvailable = __CFSocketCallBackTypes(s) & (kCFSocketWriteCallBack | kCFSocketConnectCallBack);
d8925383
A
2365 if (s->_f.connected) writeCallBacksAvailable &= ~kCFSocketConnectCallBack;
2366 if ((s->_f.disabled & writeCallBacksAvailable) != writeCallBacksAvailable) wakeup = true;
9ce05555
A
2367 }
2368 }
2369 if (readCallBackType != kCFSocketNoCallBack && (callBackTypes & readCallBackType) != 0) {
d8925383 2370 if (__CFSocketClearFDForRead(s)) {
9ce05555
A
2371 // do not wake up the socket manager thread if callback type is read
2372 if (readCallBackType != kCFSocketReadCallBack) wakeup = true;
2373 }
2374 }
2375 __CFSpinUnlock(&__CFActiveSocketsLock);
2376 }
2377 __CFSocketUnlock(s);
9ce05555
A
2378}
2379
d8925383
A
2380// "force" means to clear the disabled bits set by DisableCallBacks and always reenable.
2381// if (!force) we respect those bits, meaning they may stop us from enabling.
2382// In addition, if !force we assume that the sockets have already been added to the
2383// __CFReadSockets and __CFWriteSockets arrays. This is true because the callbacks start
2384// enabled when the CFSocket is created (at which time we enable with force).
2385// Called with SocketLock held, returns with it released!
2386void __CFSocketEnableCallBacks(CFSocketRef s, CFOptionFlags callBackTypes, Boolean force, uint8_t wakeupChar) {
bd5b749c 2387 CHECK_FOR_FORK();
d8925383
A
2388 Boolean wakeup = FALSE;
2389 if (!callBackTypes) {
2390 __CFSocketUnlock(s);
2391 return;
2392 }
2393 if (__CFSocketIsValid(s) && __CFSocketIsScheduled(s)) {
2394 Boolean turnOnWrite = FALSE, turnOnConnect = FALSE, turnOnRead = FALSE;
2395 uint8_t readCallBackType = __CFSocketReadCallBackType(s);
9ce05555 2396 callBackTypes &= __CFSocketCallBackTypes(s);
d8925383 2397 if (force) s->_f.disabled &= ~callBackTypes;
9ce05555 2398#if defined(LOG_CFSOCKET)
d8925383 2399 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);
f32021b4 2400#endif
d8925383
A
2401 /* We will wait for connection only for connection-oriented, non-rendezvous sockets that are not already connected. Mark others as already connected. */
2402 if ((readCallBackType == kCFSocketAcceptCallBack) || !__CFSocketIsConnectionOriented(s)) s->_f.connected = TRUE;
2403
2404 // First figure out what to turn on
2405 if (s->_f.connected || (callBackTypes & kCFSocketConnectCallBack) == 0) {
2406 // if we want write callbacks and they're not disabled...
2407 if ((callBackTypes & kCFSocketWriteCallBack) != 0 && (s->_f.disabled & kCFSocketWriteCallBack) == 0) turnOnWrite = TRUE;
2408 } else {
2409 // if we want connect callbacks and they're not disabled...
2410 if ((callBackTypes & kCFSocketConnectCallBack) != 0 && (s->_f.disabled & kCFSocketConnectCallBack) == 0) turnOnConnect = TRUE;
9ce05555 2411 }
d8925383
A
2412 // if we want read callbacks and they're not disabled...
2413 if (readCallBackType != kCFSocketNoCallBack && (callBackTypes & readCallBackType) != 0 && (s->_f.disabled & kCFSocketReadCallBack) == 0) turnOnRead = TRUE;
2414
2415 // Now turn on the callbacks we've determined that we want on
2416 if (turnOnRead || turnOnWrite || turnOnConnect) {
2417 __CFSpinLock(&__CFActiveSocketsLock);
d8925383
A
2418 if (turnOnWrite || turnOnConnect) {
2419 if (force) {
2420 SInt32 idx = CFArrayGetFirstIndexOfValue(__CFWriteSockets, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets)), s);
2421 if (kCFNotFound == idx) CFArrayAppendValue(__CFWriteSockets, s);
cf7d2af9 2422// if (kCFNotFound == idx) CFLog(5, CFSTR("__CFSocketEnableCallBacks: put %p in __CFWriteSockets list due to force and non-presence"), s);
d8925383
A
2423 }
2424 if (__CFSocketSetFDForWrite(s)) wakeup = true;
d8925383
A
2425 }
2426 if (turnOnRead) {
2427 if (force) {
2428 SInt32 idx = CFArrayGetFirstIndexOfValue(__CFReadSockets, CFRangeMake(0, CFArrayGetCount(__CFReadSockets)), s);
2429 if (kCFNotFound == idx) CFArrayAppendValue(__CFReadSockets, s);
2430 }
2431 if (__CFSocketSetFDForRead(s)) wakeup = true;
2432 }
d8925383 2433 __CFSpinUnlock(&__CFActiveSocketsLock);
9ce05555 2434 }
9ce05555
A
2435 }
2436 __CFSocketUnlock(s);
d8925383
A
2437}
2438
2439void CFSocketEnableCallBacks(CFSocketRef s, CFOptionFlags callBackTypes) {
bd5b749c 2440 CHECK_FOR_FORK();
cf7d2af9 2441 __CFGenericValidateType(s, CFSocketGetTypeID());
d8925383
A
2442 __CFSocketLock(s);
2443 __CFSocketEnableCallBacks(s, callBackTypes, TRUE, 'r');
cf7d2af9 2444// CFLog(5, CFSTR("CFSocketEnableCallBacks(%p, 0x%x) done"), s, callBackTypes);
9ce05555
A
2445}
2446
2447static void __CFSocketSchedule(void *info, CFRunLoopRef rl, CFStringRef mode) {
2448 CFSocketRef s = info;
9ce05555
A
2449 __CFSocketLock(s);
2450 //??? also need to arrange delivery of all pending data
2451 if (__CFSocketIsValid(s)) {
7c97c3e0
A
2452 CFMutableArrayRef runLoopsOrig = s->_runLoops;
2453 CFMutableArrayRef runLoopsCopy = CFArrayCreateMutableCopy(kCFAllocatorSystemDefault, 0, s->_runLoops);
2454 CFArrayAppendValue(runLoopsCopy, rl);
2455 s->_runLoops = runLoopsCopy;
2456 CFRelease(runLoopsOrig);
9ce05555 2457 s->_socketSetCount++;
d8925383
A
2458 // Since the v0 source is listened to on the SocketMgr thread, no matter how many modes it
2459 // is added to we just need to enable it there once (and _socketSetCount gives us a refCount
2460 // to know when we can finally disable it).
9ce05555
A
2461 if (1 == s->_socketSetCount) {
2462#if defined(LOG_CFSOCKET)
d8925383 2463 fprintf(stdout, "scheduling socket %d\n", s->_socket);
f32021b4 2464#endif
cf7d2af9 2465// CFLog(5, CFSTR("__CFSocketSchedule(%p, %p, %p)"), s, rl, mode);
d8925383
A
2466 __CFSocketEnableCallBacks(s, __CFSocketCallBackTypes(s), TRUE, 's'); // unlocks s
2467 } else
2468 __CFSocketUnlock(s);
d8925383
A
2469 } else
2470 __CFSocketUnlock(s);
9ce05555
A
2471}
2472
2473static void __CFSocketCancel(void *info, CFRunLoopRef rl, CFStringRef mode) {
2474 CFSocketRef s = info;
2475 SInt32 idx;
2476 __CFSocketLock(s);
2477 s->_socketSetCount--;
2478 if (0 == s->_socketSetCount) {
2479 __CFSpinLock(&__CFActiveSocketsLock);
9ce05555
A
2480 idx = CFArrayGetFirstIndexOfValue(__CFWriteSockets, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets)), s);
2481 if (0 <= idx) {
cf7d2af9 2482// CFLog(5, CFSTR("__CFSocketCancel: removing %p from __CFWriteSockets list"), s);
9ce05555 2483 CFArrayRemoveValueAtIndex(__CFWriteSockets, idx);
d8925383 2484 __CFSocketClearFDForWrite(s);
9ce05555
A
2485 }
2486 idx = CFArrayGetFirstIndexOfValue(__CFReadSockets, CFRangeMake(0, CFArrayGetCount(__CFReadSockets)), s);
2487 if (0 <= idx) {
2488 CFArrayRemoveValueAtIndex(__CFReadSockets, idx);
d8925383 2489 __CFSocketClearFDForRead(s);
9ce05555
A
2490 }
2491 __CFSpinUnlock(&__CFActiveSocketsLock);
2492 }
2493 if (NULL != s->_runLoops) {
7c97c3e0
A
2494 CFMutableArrayRef runLoopsOrig = s->_runLoops;
2495 CFMutableArrayRef runLoopsCopy = CFArrayCreateMutableCopy(kCFAllocatorSystemDefault, 0, s->_runLoops);
2496 idx = CFArrayGetFirstIndexOfValue(runLoopsCopy, CFRangeMake(0, CFArrayGetCount(runLoopsCopy)), rl);
2497 if (0 <= idx) CFArrayRemoveValueAtIndex(runLoopsCopy, idx);
2498 s->_runLoops = runLoopsCopy;
2499 CFRelease(runLoopsOrig);
9ce05555
A
2500 }
2501 __CFSocketUnlock(s);
2502}
2503
d8925383
A
2504// Note: must be called with socket lock held, then returns with it released
2505// Used by both the v0 and v1 RunLoopSource perform routines
2506static void __CFSocketDoCallback(CFSocketRef s, CFDataRef data, CFDataRef address, CFSocketNativeHandle sock) {
9ce05555
A
2507 CFSocketCallBack callout = NULL;
2508 void *contextInfo = NULL;
2509 SInt32 errorCode = 0;
d8925383
A
2510 Boolean readSignalled = false, writeSignalled = false, connectSignalled = false, calledOut = false;
2511 uint8_t readCallBackType, callBackTypes;
9ce05555 2512
9ce05555
A
2513 callBackTypes = __CFSocketCallBackTypes(s);
2514 readCallBackType = __CFSocketReadCallBackType(s);
2515 readSignalled = __CFSocketIsReadSignalled(s);
2516 writeSignalled = __CFSocketIsWriteSignalled(s);
d8925383 2517 connectSignalled = writeSignalled && !s->_f.connected;
9ce05555
A
2518 __CFSocketUnsetReadSignalled(s);
2519 __CFSocketUnsetWriteSignalled(s);
2520 callout = s->_callout;
2521 contextInfo = s->_context.info;
2522#if defined(LOG_CFSOCKET)
d8925383 2523 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);
f32021b4 2524#endif
9ce05555
A
2525 if (writeSignalled) {
2526 errorCode = s->_errorCode;
d8925383 2527 s->_f.connected = TRUE;
9ce05555
A
2528 }
2529 __CFSocketUnlock(s);
2530 if ((callBackTypes & kCFSocketConnectCallBack) != 0) {
2531 if (connectSignalled && (!calledOut || CFSocketIsValid(s))) {
cf7d2af9 2532// CFLog(5, CFSTR("__CFSocketPerformV0(%p) doing connect callback, error: %d"), s, errorCode);
9ce05555
A
2533 if (errorCode) {
2534#if defined(LOG_CFSOCKET)
d8925383 2535 fprintf(stdout, "perform calling out error %ld to socket %d\n", errorCode, s->_socket);
f32021b4 2536#endif
9ce05555
A
2537 if (callout) callout(s, kCFSocketConnectCallBack, NULL, &errorCode, contextInfo);
2538 calledOut = true;
2539 } else {
2540#if defined(LOG_CFSOCKET)
d8925383 2541 fprintf(stdout, "perform calling out connect to socket %d\n", s->_socket);
f32021b4 2542#endif
9ce05555
A
2543 if (callout) callout(s, kCFSocketConnectCallBack, NULL, NULL, contextInfo);
2544 calledOut = true;
2545 }
2546 }
2547 }
2548 if (kCFSocketDataCallBack == readCallBackType) {
2549 if (NULL != data && (!calledOut || CFSocketIsValid(s))) {
2550 SInt32 datalen = CFDataGetLength(data);
2551#if defined(LOG_CFSOCKET)
d8925383 2552 fprintf(stdout, "perform calling out data of length %ld to socket %d\n", datalen, s->_socket);
f32021b4 2553#endif
9ce05555
A
2554 if (callout) callout(s, kCFSocketDataCallBack, address, data, contextInfo);
2555 calledOut = true;
bd5b749c 2556 if (0 == datalen) CFSocketInvalidate(s);
9ce05555
A
2557 }
2558 } else if (kCFSocketAcceptCallBack == readCallBackType) {
2559 if (INVALID_SOCKET != sock && (!calledOut || CFSocketIsValid(s))) {
2560#if defined(LOG_CFSOCKET)
d8925383 2561 fprintf(stdout, "perform calling out accept of socket %d to socket %d\n", sock, s->_socket);
f32021b4 2562#endif
9ce05555
A
2563 if (callout) callout(s, kCFSocketAcceptCallBack, address, &sock, contextInfo);
2564 calledOut = true;
9ce05555
A
2565 }
2566 } else if (kCFSocketReadCallBack == readCallBackType) {
2567 if (readSignalled && (!calledOut || CFSocketIsValid(s))) {
2568#if defined(LOG_CFSOCKET)
d8925383 2569 fprintf(stdout, "perform calling out read to socket %d\n", s->_socket);
f32021b4 2570#endif
cf7d2af9 2571// CFLog(5, CFSTR("__CFSocketPerformV0(%p) doing read callback"), s);
9ce05555
A
2572 if (callout) callout(s, kCFSocketReadCallBack, NULL, NULL, contextInfo);
2573 calledOut = true;
2574 }
2575 }
2576 if ((callBackTypes & kCFSocketWriteCallBack) != 0) {
2577 if (writeSignalled && !errorCode && (!calledOut || CFSocketIsValid(s))) {
2578#if defined(LOG_CFSOCKET)
d8925383 2579 fprintf(stdout, "perform calling out write to socket %d\n", s->_socket);
f32021b4 2580#endif
cf7d2af9 2581// CFLog(5, CFSTR("__CFSocketPerformV0(%p) doing write callback"), s);
9ce05555
A
2582 if (callout) callout(s, kCFSocketWriteCallBack, NULL, NULL, contextInfo);
2583 calledOut = true;
2584 }
2585 }
d8925383
A
2586}
2587
d8925383
A
2588static void __CFSocketPerformV0(void *info) {
2589 CFSocketRef s = info;
2590 CFDataRef data = NULL;
2591 CFDataRef address = NULL;
2592 CFSocketNativeHandle sock = INVALID_SOCKET;
2593 uint8_t readCallBackType, callBackTypes;
2594 CFRunLoopRef rl = NULL;
cf7d2af9 2595// CFLog(5, CFSTR("__CFSocketPerformV0(%p) starting"), s);
d8925383
A
2596
2597 __CFSocketLock(s);
2598 if (!__CFSocketIsValid(s)) {
2599 __CFSocketUnlock(s);
2600 return;
2601 }
2602 callBackTypes = __CFSocketCallBackTypes(s);
2603 readCallBackType = __CFSocketReadCallBackType(s);
2604 CFOptionFlags callBacksSignalled = 0;
2605 if (__CFSocketIsReadSignalled(s)) callBacksSignalled |= readCallBackType;
2606 if (__CFSocketIsWriteSignalled(s)) callBacksSignalled |= kCFSocketWriteCallBack;
2607
d8925383
A
2608 if (kCFSocketDataCallBack == readCallBackType) {
2609 if (NULL != s->_dataQueue && 0 < CFArrayGetCount(s->_dataQueue)) {
2610 data = CFArrayGetValueAtIndex(s->_dataQueue, 0);
2611 CFRetain(data);
2612 CFArrayRemoveValueAtIndex(s->_dataQueue, 0);
2613 address = CFArrayGetValueAtIndex(s->_addressQueue, 0);
2614 CFRetain(address);
2615 CFArrayRemoveValueAtIndex(s->_addressQueue, 0);
2616 }
2617 } else if (kCFSocketAcceptCallBack == readCallBackType) {
2618 if (NULL != s->_dataQueue && 0 < CFArrayGetCount(s->_dataQueue)) {
bd5b749c 2619 sock = (CFSocketNativeHandle)(uintptr_t)CFArrayGetValueAtIndex(s->_dataQueue, 0);
d8925383
A
2620 CFArrayRemoveValueAtIndex(s->_dataQueue, 0);
2621 address = CFArrayGetValueAtIndex(s->_addressQueue, 0);
2622 CFRetain(address);
2623 CFArrayRemoveValueAtIndex(s->_addressQueue, 0);
9ce05555
A
2624 }
2625 }
d8925383
A
2626
2627 __CFSocketDoCallback(s, data, address, sock); // does __CFSocketUnlock(s)
2628 if (NULL != data) CFRelease(data);
2629 if (NULL != address) CFRelease(address);
2630
2631 __CFSocketLock(s);
d8925383
A
2632 if (__CFSocketIsValid(s) && kCFSocketNoCallBack != readCallBackType) {
2633 // if there's still more data, we want to wake back up right away
2634 if ((kCFSocketDataCallBack == readCallBackType || kCFSocketAcceptCallBack == readCallBackType) && NULL != s->_dataQueue && 0 < CFArrayGetCount(s->_dataQueue)) {
d8925383
A
2635#if defined(LOG_CFSOCKET)
2636 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);
f32021b4 2637#endif
7c97c3e0
A
2638 CFRunLoopSourceSignal(s->_source0);
2639 CFMutableArrayRef runLoopsOrig = (CFMutableArrayRef)CFRetain(s->_runLoops);
2640 CFMutableArrayRef runLoopsCopy = CFArrayCreateMutableCopy(kCFAllocatorSystemDefault, 0, s->_runLoops);
2641 CFRunLoopSourceRef source0 = s->_source0;
2642 if (NULL != source0 && !CFRunLoopSourceIsValid(source0)) {
2643 source0 = NULL;
2644 }
2645 if (source0) CFRetain(source0);
2646 __CFSocketUnlock(s);
2647 rl = __CFSocketCopyRunLoopToWakeUp(source0, runLoopsCopy);
2648 if (source0) CFRelease(source0);
2649 __CFSocketLock(s);
2650 if (runLoopsOrig == s->_runLoops) {
2651 s->_runLoops = runLoopsCopy;
2652 runLoopsCopy = NULL;
2653 CFRelease(runLoopsOrig);
2654 }
2655 CFRelease(runLoopsOrig);
2656 if (runLoopsCopy) CFRelease(runLoopsCopy);
9ce05555 2657 }
9ce05555 2658 }
d8925383
A
2659 // Only reenable callbacks that are auto-reenabled
2660 __CFSocketEnableCallBacks(s, callBacksSignalled & s->_f.client, FALSE, 'p'); // unlocks s
2661
9ce05555
A
2662 if (NULL != rl) {
2663 CFRunLoopWakeUp(rl);
2664 CFRelease(rl);
2665 }
cf7d2af9 2666// CFLog(5, CFSTR("__CFSocketPerformV0(%p) done"), s);
9ce05555
A
2667}
2668
2669CFRunLoopSourceRef CFSocketCreateRunLoopSource(CFAllocatorRef allocator, CFSocketRef s, CFIndex order) {
bd5b749c 2670 CHECK_FOR_FORK();
9ce05555 2671 CFRunLoopSourceRef result = NULL;
cf7d2af9 2672 __CFGenericValidateType(s, CFSocketGetTypeID());
9ce05555
A
2673 __CFSocketLock(s);
2674 if (__CFSocketIsValid(s)) {
7c97c3e0
A
2675 if (NULL != s->_source0 && !CFRunLoopSourceIsValid(s->_source0)) {
2676 CFRelease(s->_source0);
2677 s->_source0 = NULL;
2678 }
d8925383 2679 if (NULL == s->_source0) {
9ce05555
A
2680 CFRunLoopSourceContext context;
2681 context.version = 0;
d8925383
A
2682 context.info = s;
2683 context.retain = CFRetain;
2684 context.release = CFRelease;
2685 context.copyDescription = CFCopyDescription;
2686 context.equal = CFEqual;
2687 context.hash = CFHash;
9ce05555
A
2688 context.schedule = __CFSocketSchedule;
2689 context.cancel = __CFSocketCancel;
d8925383
A
2690 context.perform = __CFSocketPerformV0;
2691 s->_source0 = CFRunLoopSourceCreate(allocator, order, &context);
9ce05555 2692 }
d8925383
A
2693 CFRetain(s->_source0); /* This retain is for the receiver */
2694 result = s->_source0;
9ce05555
A
2695 }
2696 __CFSocketUnlock(s);
2697 return result;
2698}
2699
bd5b749c
A
2700#endif /* NEW_SOCKET */
2701
cf7d2af9
A
2702
2703
2704static uint16_t __CFSocketDefaultNameRegistryPortNumber = 2454;
2705
2706CONST_STRING_DECL(kCFSocketCommandKey, "Command")
2707CONST_STRING_DECL(kCFSocketNameKey, "Name")
2708CONST_STRING_DECL(kCFSocketValueKey, "Value")
2709CONST_STRING_DECL(kCFSocketResultKey, "Result")
2710CONST_STRING_DECL(kCFSocketErrorKey, "Error")
2711CONST_STRING_DECL(kCFSocketRegisterCommand, "Register")
2712CONST_STRING_DECL(kCFSocketRetrieveCommand, "Retrieve")
2713CONST_STRING_DECL(__kCFSocketRegistryRequestRunLoopMode, "CFSocketRegistryRequest")
2714
bd5b749c
A
2715static CFSpinLock_t __CFSocketWriteLock_ = CFSpinLockInit;
2716//#warning can only send on one socket at a time now
2717
2718CF_INLINE void __CFSocketWriteLock(CFSocketRef s) {
2719 __CFSpinLock(& __CFSocketWriteLock_);
2720}
2721
2722CF_INLINE void __CFSocketWriteUnlock(CFSocketRef s) {
2723 __CFSpinUnlock(& __CFSocketWriteLock_);
2724}
2725
cf7d2af9
A
2726#if NEW_SOCKET
2727
2728CF_INLINE CFIndex __CFSocketFdGetSize(CFDataRef fdSet) {
2729 return NBBY * CFDataGetLength(fdSet);
2730}
2731
2732CF_INLINE Boolean __CFSocketFdSet(CFSocketNativeHandle sock, CFMutableDataRef fdSet) {
2733 /* returns true if a change occurred, false otherwise */
2734 Boolean retval = false;
2735 if (INVALID_SOCKET != sock && 0 <= sock) {
2736 CFIndex numFds = NBBY * CFDataGetLength(fdSet);
2737 fd_mask *fds_bits;
2738 if (sock >= numFds) {
2739 CFIndex oldSize = numFds / NFDBITS, newSize = (sock + NFDBITS) / NFDBITS, changeInBytes = (newSize - oldSize) * sizeof(fd_mask);
2740 CFDataIncreaseLength(fdSet, changeInBytes);
2741 fds_bits = (fd_mask *)CFDataGetMutableBytePtr(fdSet);
2742 memset(fds_bits + oldSize, 0, changeInBytes);
2743 } else {
2744 fds_bits = (fd_mask *)CFDataGetMutableBytePtr(fdSet);
2745 }
2746 if (!FD_ISSET(sock, (fd_set *)fds_bits)) {
2747 retval = true;
2748 FD_SET(sock, (fd_set *)fds_bits);
2749 }
2750 }
2751 return retval;
2752}
2753
2754#endif
2755
9ce05555
A
2756//??? need timeout, error handling, retries
2757CFSocketError CFSocketSendData(CFSocketRef s, CFDataRef address, CFDataRef data, CFTimeInterval timeout) {
bd5b749c 2758 CHECK_FOR_FORK();
9ce05555
A
2759 const uint8_t *dataptr, *addrptr = NULL;
2760 SInt32 datalen, addrlen = 0, size = 0;
2761 CFSocketNativeHandle sock = INVALID_SOCKET;
2762 struct timeval tv;
bd5b749c 2763 __CFGenericValidateType(s, CFSocketGetTypeID());
9ce05555
A
2764 if (address) {
2765 addrptr = CFDataGetBytePtr(address);
2766 addrlen = CFDataGetLength(address);
2767 }
2768 dataptr = CFDataGetBytePtr(data);
2769 datalen = CFDataGetLength(data);
bd5b749c 2770 if (CFSocketIsValid(s)) sock = CFSocketGetNative(s);
9ce05555
A
2771 if (INVALID_SOCKET != sock) {
2772 CFRetain(s);
2773 __CFSocketWriteLock(s);
cf7d2af9
A
2774 tv.tv_sec = (timeout <= 0.0 || (CFTimeInterval)INT_MAX <= timeout) ? INT_MAX : (int)floor(timeout);
2775 tv.tv_usec = (int)floor(1.0e+6 * (timeout - floor(timeout)));
d8925383 2776 setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (void *)&tv, sizeof(tv)); // cast for WinSock bad API
9ce05555
A
2777 if (NULL != addrptr && 0 < addrlen) {
2778 size = sendto(sock, dataptr, datalen, 0, (struct sockaddr *)addrptr, addrlen);
2779 } else {
2780 size = send(sock, dataptr, datalen, 0);
2781 }
2782#if defined(LOG_CFSOCKET)
bd5b749c 2783 fprintf(stdout, "wrote %ld bytes to socket %d\n", size, sock);
f32021b4 2784#endif
9ce05555
A
2785 __CFSocketWriteUnlock(s);
2786 CFRelease(s);
2787 }
2788 return (size > 0) ? kCFSocketSuccess : kCFSocketError;
2789}
2790
bd5b749c
A
2791CFSocketError CFSocketSetAddress(CFSocketRef s, CFDataRef address) {
2792 CHECK_FOR_FORK();
2793 const uint8_t *name;
2794 SInt32 namelen, result = 0;
2795 __CFGenericValidateType(s, CFSocketGetTypeID());
7c97c3e0
A
2796 if (NULL == address) return kCFSocketError;
2797 if (!CFSocketIsValid(s)) return kCFSocketError;
bd5b749c
A
2798 name = CFDataGetBytePtr(address);
2799 namelen = CFDataGetLength(address);
7c97c3e0 2800 if (!name || namelen <= 0) return kCFSocketError;
bd5b749c
A
2801 CFSocketNativeHandle sock = CFSocketGetNative(s);
2802 result = bind(sock, (struct sockaddr *)name, namelen);
2803 if (0 == result) {
2804 listen(sock, 256);
2805 }
2806 //??? should return errno
2807 return result;
2808}
2809
2810CFSocketError CFSocketConnectToAddress(CFSocketRef s, CFDataRef address, CFTimeInterval timeout) {
2811 CHECK_FOR_FORK();
2812 //??? need error handling, retries
2813 const uint8_t *name;
2814 SInt32 namelen, result = -1, connect_err = 0, select_err = 0;
2815 UInt32 yes = 1, no = 0;
2816 Boolean wasBlocking = true;
2817
2818 __CFGenericValidateType(s, CFSocketGetTypeID());
7c97c3e0 2819 if (!CFSocketIsValid(s)) return kCFSocketError;
bd5b749c
A
2820 name = CFDataGetBytePtr(address);
2821 namelen = CFDataGetLength(address);
7c97c3e0 2822 if (!name || namelen <= 0) return kCFSocketError;
bd5b749c
A
2823 CFSocketNativeHandle sock = CFSocketGetNative(s);
2824 {
2825 SInt32 flags = fcntl(sock, F_GETFL, 0);
2826 if (flags >= 0) wasBlocking = ((flags & O_NONBLOCK) == 0);
cf7d2af9 2827 if (wasBlocking && (timeout > 0.0 || timeout < 0.0)) ioctl(sock, FIONBIO, &yes);
bd5b749c
A
2828 result = connect(sock, (struct sockaddr *)name, namelen);
2829 if (result != 0) {
cf7d2af9 2830 connect_err = thread_errno();
bd5b749c
A
2831 }
2832#if defined(LOG_CFSOCKET)
2833 fprintf(stdout, "connection attempt returns %ld error %ld on socket %d (flags 0x%lx blocking %d)\n", result, connect_err, sock, flags, wasBlocking);
f32021b4 2834#endif
bd5b749c
A
2835 if (EINPROGRESS == connect_err && timeout >= 0.0) {
2836 /* select on socket */
2837 SInt32 nrfds;
2838 int error_size = sizeof(select_err);
2839 struct timeval tv;
2840 CFMutableDataRef fds = CFDataCreateMutable(kCFAllocatorSystemDefault, 0);
2841 __CFSocketFdSet(sock, fds);
cf7d2af9
A
2842 tv.tv_sec = (timeout <= 0.0 || (CFTimeInterval)INT_MAX <= timeout) ? INT_MAX : (int)floor(timeout);
2843 tv.tv_usec = (int)floor(1.0e+6 * (timeout - floor(timeout)));
bd5b749c
A
2844 nrfds = select(__CFSocketFdGetSize(fds), NULL, (fd_set *)CFDataGetMutableBytePtr(fds), NULL, &tv);
2845 if (nrfds < 0) {
cf7d2af9 2846 select_err = thread_errno();
bd5b749c
A
2847 result = -1;
2848 } else if (nrfds == 0) {
2849 result = -2;
2850 } else {
2851 if (0 != getsockopt(sock, SOL_SOCKET, SO_ERROR, (void *)&select_err, (socklen_t *)&error_size)) select_err = 0;
2852 result = (select_err == 0) ? 0 : -1;
2853 }
2854 CFRelease(fds);
2855#if defined(LOG_CFSOCKET)
2856 fprintf(stdout, "timed connection attempt %s on socket %d, result %ld, select returns %ld error %ld\n", (result == 0) ? "succeeds" : "fails", sock, result, nrfds, select_err);
f32021b4 2857#endif
bd5b749c 2858 }
cf7d2af9 2859 if (wasBlocking && (timeout > 0.0 || timeout < 0.0)) ioctl(sock, FIONBIO, &no);
bd5b749c
A
2860 if (EINPROGRESS == connect_err && timeout < 0.0) {
2861 result = 0;
2862#if defined(LOG_CFSOCKET)
2863 fprintf(stdout, "connection attempt continues in background on socket %d\n", sock);
f32021b4 2864#endif
bd5b749c
A
2865 }
2866 }
2867 //??? should return errno
2868 return result;
2869}
2870
2871CFSocketRef CFSocketCreate(CFAllocatorRef allocator, SInt32 protocolFamily, SInt32 socketType, SInt32 protocol, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context) {
2872 CHECK_FOR_FORK();
2873 CFSocketNativeHandle sock = INVALID_SOCKET;
2874 CFSocketRef s = NULL;
2875 if (0 >= protocolFamily) protocolFamily = PF_INET;
2876 if (PF_INET == protocolFamily) {
2877 if (0 >= socketType) socketType = SOCK_STREAM;
2878 if (0 >= protocol && SOCK_STREAM == socketType) protocol = IPPROTO_TCP;
2879 if (0 >= protocol && SOCK_DGRAM == socketType) protocol = IPPROTO_UDP;
2880 }
2881 if (PF_LOCAL == protocolFamily && 0 >= socketType) socketType = SOCK_STREAM;
2882 sock = socket(protocolFamily, socketType, protocol);
2883 if (INVALID_SOCKET != sock) {
cf7d2af9 2884 s = CFSocketCreateWithNative(allocator, sock, callBackTypes, callout, context);
bd5b749c
A
2885 }
2886 return s;
2887}
2888
2889CFSocketRef CFSocketCreateWithSocketSignature(CFAllocatorRef allocator, const CFSocketSignature *signature, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context) {
2890 CHECK_FOR_FORK();
2891 CFSocketRef s = CFSocketCreate(allocator, signature->protocolFamily, signature->socketType, signature->protocol, callBackTypes, callout, context);
2892 if (NULL != s && (!CFSocketIsValid(s) || kCFSocketSuccess != CFSocketSetAddress(s, signature->address))) {
2893 CFSocketInvalidate(s);
2894 CFRelease(s);
2895 s = NULL;
2896 }
2897 return s;
2898}
2899
2900CFSocketRef CFSocketCreateConnectedToSocketSignature(CFAllocatorRef allocator, const CFSocketSignature *signature, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context, CFTimeInterval timeout) {
2901 CHECK_FOR_FORK();
2902 CFSocketRef s = CFSocketCreate(allocator, signature->protocolFamily, signature->socketType, signature->protocol, callBackTypes, callout, context);
2903 if (NULL != s && (!CFSocketIsValid(s) || kCFSocketSuccess != CFSocketConnectToAddress(s, signature->address, timeout))) {
2904 CFSocketInvalidate(s);
2905 CFRelease(s);
2906 s = NULL;
2907 }
2908 return s;
2909}
2910
9ce05555
A
2911typedef struct {
2912 CFSocketError *error;
2913 CFPropertyListRef *value;
2914 CFDataRef *address;
2915} __CFSocketNameRegistryResponse;
2916
2917static void __CFSocketHandleNameRegistryReply(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) {
2918 CFDataRef replyData = (CFDataRef)data;
2919 __CFSocketNameRegistryResponse *response = (__CFSocketNameRegistryResponse *)info;
2920 CFDictionaryRef replyDictionary = NULL;
2921 CFPropertyListRef value;
bd5b749c 2922 replyDictionary = CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, replyData, kCFPropertyListImmutable, NULL);
9ce05555
A
2923 if (NULL != response->error) *(response->error) = kCFSocketError;
2924 if (NULL != replyDictionary) {
2925 if (CFGetTypeID((CFTypeRef)replyDictionary) == CFDictionaryGetTypeID() && NULL != (value = CFDictionaryGetValue(replyDictionary, kCFSocketResultKey))) {
2926 if (NULL != response->error) *(response->error) = kCFSocketSuccess;
2927 if (NULL != response->value) *(response->value) = CFRetain(value);
bd5b749c 2928 if (NULL != response->address) *(response->address) = address ? CFDataCreateCopy(kCFAllocatorSystemDefault, address) : NULL;
9ce05555
A
2929 }
2930 CFRelease(replyDictionary);
2931 }
2932 CFSocketInvalidate(s);
2933}
2934
2935static void __CFSocketSendNameRegistryRequest(CFSocketSignature *signature, CFDictionaryRef requestDictionary, __CFSocketNameRegistryResponse *response, CFTimeInterval timeout) {
2936 CFDataRef requestData = NULL;
2937 CFSocketContext context = {0, response, NULL, NULL, NULL};
2938 CFSocketRef s = NULL;
2939 CFRunLoopSourceRef source = NULL;
2940 if (NULL != response->error) *(response->error) = kCFSocketError;
bd5b749c 2941 requestData = CFPropertyListCreateXMLData(kCFAllocatorSystemDefault, requestDictionary);
9ce05555
A
2942 if (NULL != requestData) {
2943 if (NULL != response->error) *(response->error) = kCFSocketTimeout;
bd5b749c 2944 s = CFSocketCreateConnectedToSocketSignature(kCFAllocatorSystemDefault, signature, kCFSocketDataCallBack, __CFSocketHandleNameRegistryReply, &context, timeout);
9ce05555
A
2945 if (NULL != s) {
2946 if (kCFSocketSuccess == CFSocketSendData(s, NULL, requestData, timeout)) {
bd5b749c 2947 source = CFSocketCreateRunLoopSource(kCFAllocatorSystemDefault, s, 0);
9ce05555
A
2948 CFRunLoopAddSource(CFRunLoopGetCurrent(), source, __kCFSocketRegistryRequestRunLoopMode);
2949 CFRunLoopRunInMode(__kCFSocketRegistryRequestRunLoopMode, timeout, false);
2950 CFRelease(source);
2951 }
2952 CFSocketInvalidate(s);
2953 CFRelease(s);
2954 }
2955 CFRelease(requestData);
2956 }
2957}
2958
2959static void __CFSocketValidateSignature(const CFSocketSignature *providedSignature, CFSocketSignature *signature, uint16_t defaultPortNumber) {
2960 struct sockaddr_in sain, *sainp;
d8925383 2961 memset(&sain, 0, sizeof(sain));
9ce05555 2962 sain.sin_len = sizeof(sain);
9ce05555
A
2963 sain.sin_family = AF_INET;
2964 sain.sin_port = htons(__CFSocketDefaultNameRegistryPortNumber);
2965 sain.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
2966 if (NULL == providedSignature) {
2967 signature->protocolFamily = PF_INET;
2968 signature->socketType = SOCK_STREAM;
2969 signature->protocol = IPPROTO_TCP;
bd5b749c 2970 signature->address = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)&sain, sizeof(sain));
9ce05555
A
2971 } else {
2972 signature->protocolFamily = providedSignature->protocolFamily;
2973 signature->socketType = providedSignature->socketType;
2974 signature->protocol = providedSignature->protocol;
2975 if (0 >= signature->protocolFamily) signature->protocolFamily = PF_INET;
2976 if (PF_INET == signature->protocolFamily) {
2977 if (0 >= signature->socketType) signature->socketType = SOCK_STREAM;
2978 if (0 >= signature->protocol && SOCK_STREAM == signature->socketType) signature->protocol = IPPROTO_TCP;
2979 if (0 >= signature->protocol && SOCK_DGRAM == signature->socketType) signature->protocol = IPPROTO_UDP;
2980 }
2981 if (NULL == providedSignature->address) {
bd5b749c 2982 signature->address = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)&sain, sizeof(sain));
9ce05555
A
2983 } else {
2984 sainp = (struct sockaddr_in *)CFDataGetBytePtr(providedSignature->address);
2985 if ((int)sizeof(struct sockaddr_in) <= CFDataGetLength(providedSignature->address) && (AF_INET == sainp->sin_family || 0 == sainp->sin_family)) {
9ce05555 2986 sain.sin_len = sizeof(sain);
9ce05555
A
2987 sain.sin_family = AF_INET;
2988 sain.sin_port = sainp->sin_port;
2989 if (0 == sain.sin_port) sain.sin_port = htons(defaultPortNumber);
2990 sain.sin_addr.s_addr = sainp->sin_addr.s_addr;
2991 if (htonl(INADDR_ANY) == sain.sin_addr.s_addr) sain.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
bd5b749c 2992 signature->address = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)&sain, sizeof(sain));
9ce05555
A
2993 } else {
2994 signature->address = CFRetain(providedSignature->address);
2995 }
2996 }
2997 }
2998}
2999
3000CFSocketError CFSocketRegisterValue(const CFSocketSignature *nameServerSignature, CFTimeInterval timeout, CFStringRef name, CFPropertyListRef value) {
3001 CFSocketSignature signature;
bd5b749c 3002 CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
9ce05555
A
3003 CFSocketError retval = kCFSocketError;
3004 __CFSocketNameRegistryResponse response = {&retval, NULL, NULL};
3005 CFDictionaryAddValue(dictionary, kCFSocketCommandKey, kCFSocketRegisterCommand);
3006 CFDictionaryAddValue(dictionary, kCFSocketNameKey, name);
3007 if (NULL != value) CFDictionaryAddValue(dictionary, kCFSocketValueKey, value);
3008 __CFSocketValidateSignature(nameServerSignature, &signature, __CFSocketDefaultNameRegistryPortNumber);
3009 __CFSocketSendNameRegistryRequest(&signature, dictionary, &response, timeout);
3010 CFRelease(dictionary);
3011 CFRelease(signature.address);
3012 return retval;
3013}
3014
3015CFSocketError CFSocketCopyRegisteredValue(const CFSocketSignature *nameServerSignature, CFTimeInterval timeout, CFStringRef name, CFPropertyListRef *value, CFDataRef *serverAddress) {
3016 CFSocketSignature signature;
bd5b749c 3017 CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
9ce05555
A
3018 CFSocketError retval = kCFSocketError;
3019 __CFSocketNameRegistryResponse response = {&retval, value, serverAddress};
3020 CFDictionaryAddValue(dictionary, kCFSocketCommandKey, kCFSocketRetrieveCommand);
3021 CFDictionaryAddValue(dictionary, kCFSocketNameKey, name);
3022 __CFSocketValidateSignature(nameServerSignature, &signature, __CFSocketDefaultNameRegistryPortNumber);
3023 __CFSocketSendNameRegistryRequest(&signature, dictionary, &response, timeout);
3024 CFRelease(dictionary);
3025 CFRelease(signature.address);
3026 return retval;
3027}
3028
3029CFSocketError CFSocketRegisterSocketSignature(const CFSocketSignature *nameServerSignature, CFTimeInterval timeout, CFStringRef name, const CFSocketSignature *signature) {
3030 CFSocketSignature validatedSignature;
3031 CFMutableDataRef data = NULL;
3032 CFSocketError retval;
3033 CFIndex length;
3034 uint8_t bytes[4];
3035 if (NULL == signature) {
3036 retval = CFSocketUnregister(nameServerSignature, timeout, name);
3037 } else {
3038 __CFSocketValidateSignature(signature, &validatedSignature, 0);
3039 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) {
3040 retval = kCFSocketError;
3041 } else {
bd5b749c 3042 data = CFDataCreateMutable(kCFAllocatorSystemDefault, sizeof(bytes) + length);
9ce05555
A
3043 bytes[0] = validatedSignature.protocolFamily;
3044 bytes[1] = validatedSignature.socketType;
3045 bytes[2] = validatedSignature.protocol;
3046 bytes[3] = length;
3047 CFDataAppendBytes(data, bytes, sizeof(bytes));
3048 CFDataAppendBytes(data, CFDataGetBytePtr(validatedSignature.address), length);
3049 retval = CFSocketRegisterValue(nameServerSignature, timeout, name, data);
3050 CFRelease(data);
3051 }
3052 CFRelease(validatedSignature.address);
3053 }
3054 return retval;
3055}
3056
3057CFSocketError CFSocketCopyRegisteredSocketSignature(const CFSocketSignature *nameServerSignature, CFTimeInterval timeout, CFStringRef name, CFSocketSignature *signature, CFDataRef *nameServerAddress) {
3058 CFDataRef data = NULL;
3059 CFSocketSignature returnedSignature;
3060 const uint8_t *ptr = NULL, *aptr = NULL;
3061 uint8_t *mptr;
3062 CFIndex length = 0;
3063 CFDataRef serverAddress = NULL;
3064 CFSocketError retval = CFSocketCopyRegisteredValue(nameServerSignature, timeout, name, (CFPropertyListRef *)&data, &serverAddress);
3065 if (NULL == data || CFGetTypeID(data) != CFDataGetTypeID() || NULL == (ptr = CFDataGetBytePtr(data)) || (length = CFDataGetLength(data)) < 4) retval = kCFSocketError;
3066 if (kCFSocketSuccess == retval && NULL != signature) {
3067 returnedSignature.protocolFamily = (SInt32)*ptr++;
3068 returnedSignature.socketType = (SInt32)*ptr++;
3069 returnedSignature.protocol = (SInt32)*ptr++;
3070 ptr++;
bd5b749c 3071 returnedSignature.address = CFDataCreate(kCFAllocatorSystemDefault, ptr, length - 4);
9ce05555
A
3072 __CFSocketValidateSignature(&returnedSignature, signature, 0);
3073 CFRelease(returnedSignature.address);
3074 ptr = CFDataGetBytePtr(signature->address);
3075 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) {
bd5b749c 3076 CFMutableDataRef address = CFDataCreateMutableCopy(kCFAllocatorSystemDefault, CFDataGetLength(signature->address), signature->address);
9ce05555
A
3077 mptr = CFDataGetMutableBytePtr(address);
3078 ((struct sockaddr_in *)mptr)->sin_addr = ((struct sockaddr_in *)aptr)->sin_addr;
3079 CFRelease(signature->address);
3080 signature->address = address;
3081 }
3082 if (NULL != nameServerAddress) *nameServerAddress = serverAddress ? CFRetain(serverAddress) : NULL;
3083 }
3084 if (NULL != data) CFRelease(data);
3085 if (NULL != serverAddress) CFRelease(serverAddress);
3086 return retval;
3087}
3088
3089CFSocketError CFSocketUnregister(const CFSocketSignature *nameServerSignature, CFTimeInterval timeout, CFStringRef name) {
3090 return CFSocketRegisterValue(nameServerSignature, timeout, name, NULL);
3091}
3092
3093CF_EXPORT void CFSocketSetDefaultNameRegistryPortNumber(uint16_t port) {
3094 __CFSocketDefaultNameRegistryPortNumber = port;
3095}
3096
3097CF_EXPORT uint16_t CFSocketGetDefaultNameRegistryPortNumber(void) {
3098 return __CFSocketDefaultNameRegistryPortNumber;
3099}
bd5b749c 3100