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