2 * Copyright (c) 2014 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 Copyright (c) 2000-2013, Apple Inc. All rights reserved.
26 Responsibility: John Iarocci
29 #include <CoreFoundation/CFRuntime.h>
30 #include <CoreFoundation/CFNumber.h>
32 #include "CFStreamInternal.h"
33 #include "CFInternal.h"
41 CFRuntimeBase _cfBase
;
43 CFErrorRef error
; // if callBacks->version < 2, this is actually a pointer to a CFStreamError
44 struct _CFStreamClient
*client
;
45 /* NOTE: CFNetwork is still using _CFStreamGetInfoPointer, and so this slot needs to stay in this position (as the fifth field in the structure) */
46 /* NOTE: This can be taken out once CFNetwork rebuilds */
47 /* NOTE: <rdar://problem/13678879> Remove comment once CFNetwork has been rebuilt */
49 const struct _CFStreamCallBacks
*callBacks
; // This will not exist (will not be allocated) if the callbacks are from our known, "blessed" set.
51 CFSpinLock_t streamLock
;
52 CFArrayRef previousRunloopsAndModes
;
53 dispatch_queue_t queue
;
58 MIN_STATUS_CODE_BIT
= 0,
60 MAX_STATUS_CODE_BIT
= 4,
62 CONSTANT_CALLBACKS
= 5,
63 CALLING_CLIENT
= 6, // MUST remain 6 since it's value is used elsewhere.
67 // Values above used to be defined and others may rely on their values
69 // Values below should not matter if they are re-ordered or shift
75 /* CALLING_CLIENT really determines whether stream events will be sent to the client immediately, or posted for the next time through the runloop. Since the client may not be prepared for re-entrancy, we must always set/clear this bit around public entry points. -- REW, 9/5/2001
76 Also, CALLING_CLIENT is now used from CFFilteredStream.c (which has a copy of the #define above). Really gross. We should find a way to avoid that.... -- REW, 3/27/2002 */
77 // Used in CFNetwork too
79 /* sSharesSources holds two mappings, one the inverse of the other, between a stream and the
80 RunLoop+RunLoopMode pair that it's scheduled in. If the stream is scheduled in more than
81 one loop or mode, it can't share RunLoopSources with others, and is not in this dict.
83 static CFSpinLock_t sSourceLock
= CFSpinLockInit
;
84 static CFMutableDictionaryRef sSharedSources
= NULL
;
86 static CFTypeID __kCFReadStreamTypeID
= _kCFRuntimeNotATypeID
;
87 static CFTypeID __kCFWriteStreamTypeID
= _kCFRuntimeNotATypeID
;
89 // Just reads the bits, for those cases where we don't want to go through any callback checking
90 #define __CFStreamGetStatus(x) __CFBitfieldGetValue((x)->flags, MAX_STATUS_CODE_BIT, MIN_STATUS_CODE_BIT)
92 CF_PRIVATE CFStreamStatus
_CFStreamGetStatus(struct _CFStream
*stream
);
93 static Boolean
_CFStreamRemoveRunLoopAndModeFromArray(CFMutableArrayRef runLoopsAndModes
, CFRunLoopRef rl
, CFStringRef mode
);
94 static void _wakeUpRunLoop(struct _CFStream
*stream
);
96 CF_INLINE
void checkRLMArray(CFArrayRef arr
)
99 assert(arr
== NULL
|| (CFArrayGetCount(arr
) % 2) == 0);
103 CF_INLINE
void _CFStreamLock(struct _CFStream
* stream
) {
104 __CFSpinLock(&stream
->streamLock
);
107 CF_INLINE
void _CFStreamUnlock(struct _CFStream
* stream
) {
108 __CFSpinUnlock(&stream
->streamLock
);
111 CF_INLINE CFRunLoopSourceRef
_CFStreamCopySource(struct _CFStream
* stream
) {
112 CFRunLoopSourceRef source
= NULL
;
115 _CFStreamLock(stream
);
118 source
= stream
->client
->rlSource
;
123 _CFStreamUnlock(stream
);
129 CF_INLINE
void _CFStreamSetSource(struct _CFStream
* stream
, CFRunLoopSourceRef source
, Boolean invalidateOldSource
) {
130 CFRunLoopSourceRef oldSource
= NULL
;
133 _CFStreamLock(stream
);
134 if (stream
->client
) {
135 oldSource
= stream
->client
->rlSource
;
136 if (oldSource
!= NULL
)
139 stream
->client
->rlSource
= source
;
143 _CFStreamUnlock(stream
);
147 // Lose our extra retain
148 CFRelease(oldSource
);
150 if (invalidateOldSource
)
151 CFRunLoopSourceInvalidate(oldSource
);
153 // And lose the one that held it in our stream as well
154 CFRelease(oldSource
);
158 CF_INLINE
const struct _CFStreamCallBacks
*_CFStreamGetCallBackPtr(struct _CFStream
*stream
) {
159 return stream
->callBacks
;
162 CF_INLINE
void _CFStreamSetStatusCode(struct _CFStream
*stream
, CFStreamStatus newStatus
) {
163 CFStreamStatus status
= __CFStreamGetStatus(stream
);
164 if (((status
!= kCFStreamStatusClosed
) && (status
!= kCFStreamStatusError
)) ||
165 ((status
== kCFStreamStatusClosed
) && (newStatus
== kCFStreamStatusError
)))
167 __CFBitfieldSetValue(stream
->flags
, MAX_STATUS_CODE_BIT
, MIN_STATUS_CODE_BIT
, newStatus
);
171 CF_INLINE
void _CFStreamScheduleEvent(struct _CFStream
*stream
, CFStreamEventType event
) {
172 if (stream
->client
&& (stream
->client
->when
& event
)) {
173 CFRunLoopSourceRef source
= _CFStreamCopySource(stream
);
175 stream
->client
->whatToSignal
|= event
;
177 CFRunLoopSourceSignal(source
);
179 _wakeUpRunLoop(stream
);
184 CF_INLINE
void _CFStreamSetStreamError(struct _CFStream
*stream
, CFStreamError
*err
) {
185 if (!stream
->error
) {
186 stream
->error
= (CFErrorRef
)CFAllocatorAllocate(CFGetAllocator(stream
), sizeof(CFStreamError
), 0);
188 memmove(stream
->error
, err
, sizeof(CFStreamError
));
191 static CFStringRef
__CFStreamCopyDescription(CFTypeRef cf
) {
192 struct _CFStream
*stream
= (struct _CFStream
*)cf
;
193 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
194 CFStringRef contextDescription
;
196 if (cb
->copyDescription
) {
197 if (cb
->version
== 0) {
198 contextDescription
= ((CFStringRef(*)(void *))cb
->copyDescription
)(_CFStreamGetInfoPointer(stream
));
200 contextDescription
= cb
->copyDescription(stream
, _CFStreamGetInfoPointer(stream
));
203 contextDescription
= CFStringCreateWithFormat(CFGetAllocator(stream
), NULL
, CFSTR("info = %p"), _CFStreamGetInfoPointer(stream
));
205 if (CFGetTypeID(cf
) == __kCFReadStreamTypeID
) {
206 desc
= CFStringCreateWithFormat(CFGetAllocator(stream
), NULL
, CFSTR("<CFReadStream %p>{%@}"), stream
, contextDescription
);
208 desc
= CFStringCreateWithFormat(CFGetAllocator(stream
), NULL
, CFSTR("<CFWriteStream %p>{%@}"), stream
, contextDescription
);
210 CFRelease(contextDescription
);
214 static void _CFStreamDetachSource(struct _CFStream
* stream
) {
215 if (stream
&& stream
->client
&& stream
->client
->rlSource
) {
216 if (!__CFBitIsSet(stream
->flags
, SHARED_SOURCE
)) {
217 _CFStreamSetSource(stream
, NULL
, TRUE
);
221 CFArrayRef runLoopAndSourceKey
;
222 CFMutableArrayRef list
;
226 __CFSpinLock(&sSourceLock
);
228 runLoopAndSourceKey
= (CFArrayRef
)CFDictionaryGetValue(sSharedSources
, stream
);
229 list
= (CFMutableArrayRef
)CFDictionaryGetValue(sSharedSources
, runLoopAndSourceKey
);
231 count
= CFArrayGetCount(list
);
232 i
= CFArrayGetFirstIndexOfValue(list
, CFRangeMake(0, count
), stream
);
233 if (i
!= kCFNotFound
) {
234 CFArrayRemoveValueAtIndex(list
, i
);
238 CFAssert(CFArrayGetFirstIndexOfValue(list
, CFRangeMake(0, CFArrayGetCount(list
)), stream
) == kCFNotFound
, __kCFLogAssertion
, "CFStreamClose: stream found twice in its shared source's list");
241 CFRunLoopSourceRef source
= _CFStreamCopySource(stream
);
243 CFRunLoopRemoveSource((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoopAndSourceKey
, 0), source
, (CFStringRef
)CFArrayGetValueAtIndex(runLoopAndSourceKey
, 1));
246 CFDictionaryRemoveValue(sSharedSources
, runLoopAndSourceKey
);
249 CFDictionaryRemoveValue(sSharedSources
, stream
);
251 _CFStreamSetSource(stream
, NULL
, count
== 0);
253 __CFBitClear(stream
->flags
, SHARED_SOURCE
);
255 __CFSpinUnlock(&sSourceLock
);
260 CF_PRIVATE
void _CFStreamClose(struct _CFStream
*stream
) {
261 CFStreamStatus status
= _CFStreamGetStatus(stream
);
262 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
263 if (status
== kCFStreamStatusNotOpen
|| status
== kCFStreamStatusClosed
|| (status
== kCFStreamStatusError
&& __CFBitIsSet(stream
->flags
, HAVE_CLOSED
))) {
264 // Stream is not open from the client's perspective; do not callout and do not update our status to "closed"
267 if (! __CFBitIsSet(stream
->flags
, HAVE_CLOSED
)) {
268 __CFBitSet(stream
->flags
, HAVE_CLOSED
);
269 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
271 cb
->close(stream
, _CFStreamGetInfoPointer(stream
));
273 if (stream
->client
) {
274 _CFStreamDetachSource(stream
);
276 _CFStreamSetStatusCode(stream
, kCFStreamStatusClosed
);
277 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
281 //static int numStreamInstances = 0;
283 static void __CFStreamDeallocate(CFTypeRef cf
) {
284 struct _CFStream
*stream
= (struct _CFStream
*)cf
;
285 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
286 CFAllocatorRef alloc
= CFGetAllocator(stream
);
287 // numStreamInstances --;
290 _CFStreamClose(stream
);
292 if (stream
->client
) {
293 CFStreamClientContext
*cbContext
;
294 cbContext
= &(stream
->client
->cbContext
);
295 if (cbContext
->info
&& cbContext
->release
) {
296 cbContext
->release(cbContext
->info
);
299 if (stream
->client
->runLoopsAndModes
) {
300 CFRelease(stream
->client
->runLoopsAndModes
);
303 CFAllocatorDeallocate(alloc
, stream
->client
);
304 stream
->client
= NULL
; // Just in case finalize, below, calls back in to us
307 if (cb
->version
== 0) {
308 ((void(*)(void *))cb
->finalize
)(_CFStreamGetInfoPointer(stream
));
310 cb
->finalize(stream
, _CFStreamGetInfoPointer(stream
));
314 if (cb
->version
< 2) {
315 CFAllocatorDeallocate(alloc
, stream
->error
);
317 CFRelease(stream
->error
);
320 if (!__CFBitIsSet(stream
->flags
, CONSTANT_CALLBACKS
)) {
321 CFAllocatorDeallocate(alloc
, (void *)stream
->callBacks
);
323 if (stream
->previousRunloopsAndModes
) {
324 CFRelease(stream
->previousRunloopsAndModes
);
325 stream
->previousRunloopsAndModes
= NULL
;
328 dispatch_release(stream
->queue
);
329 stream
->queue
= NULL
;
333 static const CFRuntimeClass __CFReadStreamClass
= {
338 __CFStreamDeallocate
,
341 NULL
, // copyHumanDesc
342 __CFStreamCopyDescription
345 static const CFRuntimeClass __CFWriteStreamClass
= {
350 __CFStreamDeallocate
,
353 NULL
, // copyHumanDesc
354 __CFStreamCopyDescription
357 CONST_STRING_DECL(kCFStreamPropertySocketNativeHandle
, "kCFStreamPropertySocketNativeHandle")
358 CONST_STRING_DECL(kCFStreamPropertySocketRemoteHostName
, "kCFStreamPropertySocketRemoteHostName")
359 CONST_STRING_DECL(kCFStreamPropertySocketRemotePortNumber
, "kCFStreamPropertySocketRemotePortNumber")
360 CONST_STRING_DECL(kCFStreamPropertyDataWritten
, "kCFStreamPropertyDataWritten")
361 CONST_STRING_DECL(kCFStreamPropertyAppendToFile
, "kCFStreamPropertyAppendToFile")
363 CF_PRIVATE
void __CFStreamInitialize(void) {
364 __kCFReadStreamTypeID
= _CFRuntimeRegisterClass(&__CFReadStreamClass
);
365 __kCFWriteStreamTypeID
= _CFRuntimeRegisterClass(&__CFWriteStreamClass
);
369 CF_EXPORT CFTypeID
CFReadStreamGetTypeID(void) {
370 return __kCFReadStreamTypeID
;
373 CF_EXPORT CFTypeID
CFWriteStreamGetTypeID(void) {
374 return __kCFWriteStreamTypeID
;
377 static struct _CFStream
*_CFStreamCreate(CFAllocatorRef allocator
, Boolean isReadStream
) {
378 struct _CFStream
*newStream
= (struct _CFStream
*)_CFRuntimeCreateInstance(allocator
, isReadStream
? __kCFReadStreamTypeID
: __kCFWriteStreamTypeID
, sizeof(struct _CFStream
) - sizeof(CFRuntimeBase
), NULL
);
380 // numStreamInstances ++;
381 newStream
->flags
= 0;
382 _CFStreamSetStatusCode(newStream
, kCFStreamStatusNotOpen
);
383 newStream
->error
= NULL
;
384 newStream
->client
= NULL
;
385 newStream
->info
= NULL
;
386 newStream
->callBacks
= NULL
;
388 newStream
->streamLock
= CFSpinLockInit
;
389 newStream
->previousRunloopsAndModes
= NULL
;
390 newStream
->queue
= NULL
;
395 CF_EXPORT
void* _CFStreamGetInfoPointer(struct _CFStream
* stream
) {
396 return stream
== NULL
? NULL
: stream
->info
;
399 CF_PRIVATE
struct _CFStream
*_CFStreamCreateWithConstantCallbacks(CFAllocatorRef alloc
, void *info
, const struct _CFStreamCallBacks
*cb
, Boolean isReading
) {
400 struct _CFStream
*newStream
;
401 if (cb
->version
!= 1) return NULL
;
402 newStream
= _CFStreamCreate(alloc
, isReading
);
404 __CFBitSet(newStream
->flags
, CONSTANT_CALLBACKS
);
405 newStream
->callBacks
= cb
;
407 newStream
->info
= cb
->create(newStream
, info
);
409 newStream
->info
= info
;
415 CF_EXPORT
void _CFStreamSetInfoPointer(struct _CFStream
*stream
, void *info
, const struct _CFStreamCallBacks
*cb
) {
416 if (info
!= stream
->info
) {
417 if (stream
->callBacks
->finalize
) {
418 stream
->callBacks
->finalize(stream
, stream
->info
);
421 stream
->info
= cb
->create(stream
, info
);
426 stream
->callBacks
= cb
;
430 CF_EXPORT CFReadStreamRef
CFReadStreamCreate(CFAllocatorRef alloc
, const CFReadStreamCallBacks
*callbacks
, void *info
) {
431 struct _CFStream
*newStream
= _CFStreamCreate(alloc
, TRUE
);
432 struct _CFStreamCallBacks
*cb
;
433 if (!newStream
) return NULL
;
434 cb
= (struct _CFStreamCallBacks
*)CFAllocatorAllocate(alloc
, sizeof(struct _CFStreamCallBacks
), 0);
436 CFRelease(newStream
);
439 if (callbacks
->version
== 0) {
440 CFReadStreamCallBacksV0
*cbV0
= (CFReadStreamCallBacksV0
*)callbacks
;
441 CFStreamClientContext
*ctxt
= (CFStreamClientContext
*)info
;
442 newStream
->info
= ctxt
->retain
? (void *)ctxt
->retain(ctxt
->info
) : ctxt
->info
;
444 cb
->create
= (void *(*)(struct _CFStream
*, void *))ctxt
->retain
;
445 cb
->finalize
= (void(*)(struct _CFStream
*, void *))ctxt
->release
;
446 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))ctxt
->copyDescription
;
447 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))cbV0
->open
;
448 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))cbV0
->openCompleted
;
449 cb
->read
= (CFIndex (*)(CFReadStreamRef
, UInt8
*, CFIndex
, CFErrorRef
*, Boolean
*, void *))cbV0
->read
;
450 cb
->getBuffer
= (const UInt8
*(*)(CFReadStreamRef
, CFIndex
, CFIndex
*, CFErrorRef
*, Boolean
*, void *))cbV0
->getBuffer
;
451 cb
->canRead
= (Boolean (*)(CFReadStreamRef
, CFErrorRef
*, void*))cbV0
->canRead
;
454 cb
->close
= (void (*)(struct _CFStream
*, void *))cbV0
->close
;
455 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))cbV0
->copyProperty
;
456 cb
->setProperty
= NULL
;
457 cb
->requestEvents
= NULL
;
458 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV0
->schedule
;
459 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV0
->unschedule
;
460 } else if (callbacks
->version
== 1) {
461 CFReadStreamCallBacksV1
*cbV1
= (CFReadStreamCallBacksV1
*)callbacks
;
462 newStream
->info
= cbV1
->create
? cbV1
->create((CFReadStreamRef
)newStream
, info
) : info
;
464 cb
->create
= (void *(*)(struct _CFStream
*, void *))cbV1
->create
;
465 cb
->finalize
= (void(*)(struct _CFStream
*, void *))cbV1
->finalize
;
466 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))cbV1
->copyDescription
;
467 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))cbV1
->open
;
468 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))cbV1
->openCompleted
;
469 cb
->read
= (CFIndex (*)(CFReadStreamRef
, UInt8
*, CFIndex
, CFErrorRef
*, Boolean
*, void *))cbV1
->read
;
470 cb
->getBuffer
= (const UInt8
*(*)(CFReadStreamRef
, CFIndex
, CFIndex
*, CFErrorRef
*, Boolean
*, void *))cbV1
->getBuffer
;
471 cb
->canRead
= (Boolean (*)(CFReadStreamRef
, CFErrorRef
*, void*))cbV1
->canRead
;
474 cb
->close
= (void (*)(struct _CFStream
*, void *))cbV1
->close
;
475 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))cbV1
->copyProperty
;
476 cb
->setProperty
= (Boolean(*)(struct _CFStream
*, CFStringRef
, CFTypeRef
, void *))cbV1
->setProperty
;
477 cb
->requestEvents
= (void(*)(struct _CFStream
*, CFOptionFlags
, void *))cbV1
->requestEvents
;
478 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV1
->schedule
;
479 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV1
->unschedule
;
481 newStream
->info
= callbacks
->create
? callbacks
->create((CFReadStreamRef
)newStream
, info
) : info
;
483 cb
->create
= (void *(*)(struct _CFStream
*, void *))callbacks
->create
;
484 cb
->finalize
= (void(*)(struct _CFStream
*, void *))callbacks
->finalize
;
485 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))callbacks
->copyDescription
;
486 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))callbacks
->open
;
487 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))callbacks
->openCompleted
;
488 cb
->read
= callbacks
->read
;
489 cb
->getBuffer
= callbacks
->getBuffer
;
490 cb
->canRead
= callbacks
->canRead
;
493 cb
->close
= (void (*)(struct _CFStream
*, void *))callbacks
->close
;
494 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))callbacks
->copyProperty
;
495 cb
->setProperty
= (Boolean(*)(struct _CFStream
*, CFStringRef
, CFTypeRef
, void *))callbacks
->setProperty
;
496 cb
->requestEvents
= (void(*)(struct _CFStream
*, CFOptionFlags
, void *))callbacks
->requestEvents
;
497 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))callbacks
->schedule
;
498 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))callbacks
->unschedule
;
501 newStream
->callBacks
= cb
;
502 return (CFReadStreamRef
)newStream
;
505 CF_EXPORT CFWriteStreamRef
CFWriteStreamCreate(CFAllocatorRef alloc
, const CFWriteStreamCallBacks
*callbacks
, void *info
) {
506 struct _CFStream
*newStream
= _CFStreamCreate(alloc
, FALSE
);
507 struct _CFStreamCallBacks
*cb
;
508 if (!newStream
) return NULL
;
509 cb
= (struct _CFStreamCallBacks
*)CFAllocatorAllocate(alloc
, sizeof(struct _CFStreamCallBacks
), 0);
511 CFRelease(newStream
);
514 if (callbacks
->version
== 0) {
515 CFWriteStreamCallBacksV0
*cbV0
= (CFWriteStreamCallBacksV0
*)callbacks
;
516 CFStreamClientContext
*ctxt
= (CFStreamClientContext
*)info
;
517 newStream
->info
= ctxt
->retain
? (void *)ctxt
->retain(ctxt
->info
) : ctxt
->info
;
519 cb
->create
= (void *(*)(struct _CFStream
*, void *))ctxt
->retain
;
520 cb
->finalize
= (void(*)(struct _CFStream
*, void *))ctxt
->release
;
521 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))ctxt
->copyDescription
;
522 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))cbV0
->open
;
523 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))cbV0
->openCompleted
;
525 cb
->getBuffer
= NULL
;
527 cb
->write
= (CFIndex(*)(CFWriteStreamRef stream
, const UInt8
*buffer
, CFIndex bufferLength
, CFErrorRef
*error
, void *info
))cbV0
->write
;
528 cb
->canWrite
= (Boolean(*)(CFWriteStreamRef stream
, CFErrorRef
*error
, void *info
))cbV0
->canWrite
;
529 cb
->close
= (void (*)(struct _CFStream
*, void *))cbV0
->close
;
530 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))cbV0
->copyProperty
;
531 cb
->setProperty
= NULL
;
532 cb
->requestEvents
= NULL
;
533 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV0
->schedule
;
534 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV0
->unschedule
;
535 } else if (callbacks
->version
== 1) {
536 CFWriteStreamCallBacksV1
*cbV1
= (CFWriteStreamCallBacksV1
*)callbacks
;
538 newStream
->info
= cbV1
->create
? cbV1
->create((CFWriteStreamRef
)newStream
, info
) : info
;
539 cb
->create
= (void *(*)(struct _CFStream
*, void *))cbV1
->create
;
540 cb
->finalize
= (void(*)(struct _CFStream
*, void *))cbV1
->finalize
;
541 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))cbV1
->copyDescription
;
542 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))cbV1
->open
;
543 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))cbV1
->openCompleted
;
545 cb
->getBuffer
= NULL
;
547 cb
->write
= (CFIndex(*)(CFWriteStreamRef stream
, const UInt8
*buffer
, CFIndex bufferLength
, CFErrorRef
*error
, void *info
))cbV1
->write
;
548 cb
->canWrite
= (Boolean(*)(CFWriteStreamRef stream
, CFErrorRef
*error
, void *info
))cbV1
->canWrite
;
549 cb
->close
= (void (*)(struct _CFStream
*, void *))cbV1
->close
;
550 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))cbV1
->copyProperty
;
551 cb
->setProperty
= (Boolean (*)(struct _CFStream
*, CFStringRef
, CFTypeRef
, void *))cbV1
->setProperty
;
552 cb
->requestEvents
= (void(*)(struct _CFStream
*, CFOptionFlags
, void *))cbV1
->requestEvents
;
553 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV1
->schedule
;
554 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV1
->unschedule
;
556 cb
->version
= callbacks
->version
;
557 newStream
->info
= callbacks
->create
? callbacks
->create((CFWriteStreamRef
)newStream
, info
) : info
;
558 cb
->create
= (void *(*)(struct _CFStream
*, void *))callbacks
->create
;
559 cb
->finalize
= (void(*)(struct _CFStream
*, void *))callbacks
->finalize
;
560 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))callbacks
->copyDescription
;
561 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))callbacks
->open
;
562 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))callbacks
->openCompleted
;
564 cb
->getBuffer
= NULL
;
566 cb
->write
= callbacks
->write
;
567 cb
->canWrite
= callbacks
->canWrite
;
568 cb
->close
= (void (*)(struct _CFStream
*, void *))callbacks
->close
;
569 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))callbacks
->copyProperty
;
570 cb
->setProperty
= (Boolean (*)(struct _CFStream
*, CFStringRef
, CFTypeRef
, void *))callbacks
->setProperty
;
571 cb
->requestEvents
= (void(*)(struct _CFStream
*, CFOptionFlags
, void *))callbacks
->requestEvents
;
572 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))callbacks
->schedule
;
573 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))callbacks
->unschedule
;
575 newStream
->callBacks
= cb
;
576 return (CFWriteStreamRef
)newStream
;
579 static void _signalEventSync(struct _CFStream
* stream
, CFOptionFlags whatToSignal
)
581 CFOptionFlags eventMask
;
583 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
585 _CFStreamLock(stream
);
587 struct _CFStreamClient
* client
= stream
->client
;
588 if (client
== NULL
) {
589 _CFStreamUnlock(stream
);
592 void (*release
) (void*) = NULL
;
593 void (*cb
)(struct _CFStream
*, CFStreamEventType
, void *) = client
== NULL
? NULL
: client
->cb
;
595 if (stream
->client
->cbContext
.retain
== NULL
)
596 info
= stream
->client
->cbContext
.info
;
598 info
= stream
->client
->cbContext
.retain(stream
->client
->cbContext
.info
);
599 release
= stream
->client
->cbContext
.release
;
601 _CFStreamUnlock(stream
);
603 for (eventMask
= 1; eventMask
<= whatToSignal
; eventMask
= eventMask
<< 1) {
604 _CFStreamLock(stream
);
605 Boolean shouldSignal
= ((eventMask
& whatToSignal
) && stream
->client
&& (stream
->client
->when
& eventMask
));
606 _CFStreamUnlock(stream
);
608 if (shouldSignal
&& client
) {
609 cb(stream
, eventMask
, info
);
611 /* What happens if the callback sets the client to NULL? We're in a loop here... Hmm. */
612 /* After writing that comment, I see: <rdar://problem/6793636> CFReadStreamSetClient(..., NULL) unsafely releases info pointer immediately */
613 /* Of note, when the stream callbacks are set to to NULL, we're re-initalized so as not to receive more events, so we
614 * should break pout of this loop */
621 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
624 static void _signalEventQueue(dispatch_queue_t q
, struct _CFStream
* stream
, CFOptionFlags whatToSignal
)
628 _signalEventSync(stream
, whatToSignal
);
633 static void _cfstream_solo_signalEventSync(void* info
)
635 CFTypeID typeID
= CFGetTypeID((CFTypeRef
) info
);
637 if (typeID
!= CFReadStreamGetTypeID() && typeID
!= CFWriteStreamGetTypeID()) {
638 CFLog(__kCFLogAssertion
, CFSTR("Expected a read or write stream for %p"), info
);
643 struct _CFStream
* stream
= (struct _CFStream
*) info
;
644 _CFStreamLock(stream
);
645 CFOptionFlags whatToSignal
= stream
->client
->whatToSignal
;
646 stream
->client
->whatToSignal
= 0;
647 dispatch_queue_t queue
= stream
->queue
;
648 if (queue
) dispatch_retain(queue
);
650 _CFStreamUnlock(stream
);
652 /* Since the array version holds a retain, we do it here as well, as opposed to taking a second retain in the client callback */
654 _signalEventSync(stream
, whatToSignal
);
656 _signalEventQueue(queue
, stream
, whatToSignal
);
657 dispatch_release(queue
);
663 static void _cfstream_shared_signalEventSync(void* info
)
665 CFTypeID typeID
= CFGetTypeID((CFTypeRef
) info
);
667 if (typeID
!= CFArrayGetTypeID()) {
668 CFLog(__kCFLogAssertion
, CFSTR("Expected an array for %p"), info
);
673 CFMutableArrayRef list
= (CFMutableArrayRef
) info
;
675 CFOptionFlags whatToSignal
= 0;
676 dispatch_queue_t queue
= 0;
677 struct _CFStream
* stream
= NULL
;
679 __CFSpinLock(&sSourceLock
);
681 /* Looks like, we grab the first stream that wants an event... */
682 /* Note that I grab an extra retain when I pull out the stream here... */
683 c
= CFArrayGetCount(list
);
684 for (i
= 0; i
< c
; i
++) {
685 struct _CFStream
* s
= (struct _CFStream
*)CFArrayGetValueAtIndex(list
, i
);
687 if (s
->client
->whatToSignal
) {
690 whatToSignal
= stream
->client
->whatToSignal
;
691 s
->client
->whatToSignal
= 0;
692 queue
= stream
->queue
;
693 if (queue
) dispatch_retain(queue
);
698 /* And then we also signal any other streams in this array so that we get them next go? */
700 struct _CFStream
* s
= (struct _CFStream
*)CFArrayGetValueAtIndex(list
, i
);
701 if (s
->client
->whatToSignal
) {
702 CFRunLoopSourceRef source
= _CFStreamCopySource(s
);
704 CFRunLoopSourceSignal(source
);
711 __CFSpinUnlock(&sSourceLock
);
713 /* We're sitting here now, possibly with a stream that needs to be processed by the common routine */
716 _signalEventSync(stream
, whatToSignal
);
718 _signalEventQueue(queue
, stream
, whatToSignal
);
719 dispatch_release(queue
);
722 /* Lose our extra retain */
728 /* This routine is to be considered unsafe... */
729 static CFArrayRef
_CFStreamGetRunLoopsAndModes(struct _CFStream
*stream
)
731 CFArrayRef result
= NULL
;
732 if (stream
&& stream
->client
) {
733 _CFStreamLock(stream
);
734 if (stream
->previousRunloopsAndModes
) {
735 CFRelease(stream
->previousRunloopsAndModes
);
736 stream
->previousRunloopsAndModes
= NULL
;
738 if (stream
->client
->runLoopsAndModes
) {
739 stream
->previousRunloopsAndModes
= CFArrayCreateCopy(CFGetAllocator(stream
), stream
->client
->runLoopsAndModes
);
741 result
= stream
->previousRunloopsAndModes
;
742 checkRLMArray(result
);
743 _CFStreamUnlock(stream
);
748 static CFArrayRef
_CFStreamCopyRunLoopsAndModes(struct _CFStream
*stream
)
750 CFArrayRef result
= NULL
;
751 if (stream
&& stream
->client
) {
752 _CFStreamLock(stream
);
753 if (stream
->client
->runLoopsAndModes
) {
754 result
= CFArrayCreateCopy(CFGetAllocator(stream
), stream
->client
->runLoopsAndModes
);
756 checkRLMArray(result
);
757 _CFStreamUnlock(stream
);
762 static void _wakeUpRunLoop(struct _CFStream
*stream
) {
763 CFArrayRef rlArray
= _CFStreamCopyRunLoopsAndModes(stream
);
765 CFIndex cnt
= CFArrayGetCount(rlArray
);
766 CFRunLoopRef rl
= NULL
;
769 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, 0);
770 } else if (cnt
> 2) {
772 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, 0);
773 for (idx
= 2; NULL
!= rl
&& idx
< cnt
; idx
+=2) {
774 CFRunLoopRef value
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, idx
);
775 if (value
!= rl
) rl
= NULL
;
777 if (NULL
== rl
) { /* more than one different rl, so we must pick one */
778 for (idx
= 0; idx
< cnt
; idx
+=2) {
779 CFRunLoopRef value
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, idx
);
780 CFStringRef currentMode
= CFRunLoopCopyCurrentMode(value
);
781 if (NULL
!= currentMode
&& CFEqual(currentMode
, CFArrayGetValueAtIndex(rlArray
, idx
+1)) && CFRunLoopIsWaiting(value
)) {
782 CFRelease(currentMode
);
786 if (NULL
!= currentMode
) CFRelease(currentMode
);
788 if (NULL
== rl
) { /* didn't choose one above, so choose first */
789 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, 0);
793 if (NULL
!= rl
&& CFRunLoopIsWaiting(rl
))
799 CF_PRIVATE
void _CFStreamSignalEvent(struct _CFStream
*stream
, CFStreamEventType event
, CFErrorRef error
, Boolean synchronousAllowed
) {
800 // Update our internal status; we must use the primitive __CFStreamGetStatus(), because CFStreamGetStatus() calls us, and we can end up in an infinite loop.
801 CFStreamStatus status
= __CFStreamGetStatus(stream
);
803 // Sanity check the event
804 if (status
== kCFStreamStatusNotOpen
) {
805 // No events allowed; this is almost certainly a bug in the stream's implementation
806 CFLog(__kCFLogAssertion
, CFSTR("Stream %p is sending an event before being opened"), stream
);
808 } else if (status
== kCFStreamStatusClosed
|| status
== kCFStreamStatusError
) {
809 // no further events are allowed
811 } else if (status
== kCFStreamStatusAtEnd
) {
812 // Only error events are allowed
813 event
&= kCFStreamEventErrorOccurred
;
814 } else if (status
!= kCFStreamStatusOpening
) {
815 // cannot send open completed; that happened already
816 event
&= ~kCFStreamEventOpenCompleted
;
819 // Change status if appropriate
820 if (event
& kCFStreamEventOpenCompleted
&& status
== kCFStreamStatusOpening
) {
821 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
823 if (event
& kCFStreamEventEndEncountered
&& status
< kCFStreamStatusAtEnd
) {
824 _CFStreamSetStatusCode(stream
, kCFStreamStatusAtEnd
);
826 if (event
& kCFStreamEventErrorOccurred
) {
827 if (_CFStreamGetCallBackPtr(stream
)->version
< 2) {
828 _CFStreamSetStreamError(stream
, (CFStreamError
*)error
);
830 CFAssert(error
, __kCFLogAssertion
, "CFStream: kCFStreamEventErrorOccurred signalled, but error is NULL!");
832 if (stream
->error
) CFRelease(stream
->error
);
833 stream
->error
= error
;
835 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
838 // Now signal any pertinent event
839 if (stream
->client
&& (stream
->client
->when
& event
) != 0) {
840 CFRunLoopSourceRef source
= _CFStreamCopySource(stream
);
843 Boolean signalNow
= FALSE
;
845 stream
->client
->whatToSignal
|= event
;
847 if (synchronousAllowed
&& !__CFBitIsSet(stream
->flags
, CALLING_CLIENT
)) {
849 CFRunLoopRef rl
= CFRunLoopGetCurrent();
850 CFStringRef mode
= CFRunLoopCopyCurrentMode(rl
);
853 if (CFRunLoopContainsSource(rl
, source
, mode
))
861 // Can call out safely right now
862 _cfstream_solo_signalEventSync(stream
);
864 // Schedule for later delivery
866 CFRunLoopSourceSignal(source
);
868 _wakeUpRunLoop(stream
);
876 CF_PRIVATE CFStreamStatus
_CFStreamGetStatus(struct _CFStream
*stream
) {
877 CFStreamStatus status
= __CFStreamGetStatus(stream
);
878 // Status code just represents the value when last we checked; if we were in the middle of doing work at that time, we need to find out if the work has completed, now. If we find out about a status change, we need to inform the client as well, so we call _CFStreamSignalEvent. This will take care of updating our internal status correctly, too.
879 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
880 if (status
== kCFStreamStatusOpening
) {
881 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
882 if (cb
->openCompleted
) {
884 if (cb
->version
< 2) {
885 CFStreamError err
= {0, 0};
886 isComplete
= ((_CFStreamCBOpenCompletedV1
)(cb
->openCompleted
))(stream
, &err
, _CFStreamGetInfoPointer(stream
));
887 if (err
.error
!= 0) _CFStreamSetStreamError(stream
, &err
);
889 isComplete
= cb
->openCompleted(stream
, &(stream
->error
), _CFStreamGetInfoPointer(stream
));
892 if (!stream
->error
) {
893 status
= kCFStreamStatusOpen
;
895 status
= kCFStreamStatusError
;
897 _CFStreamSetStatusCode(stream
, status
);
898 if (status
== kCFStreamStatusOpen
) {
899 _CFStreamScheduleEvent(stream
, kCFStreamEventOpenCompleted
);
901 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
906 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
910 CF_EXPORT CFStreamStatus
CFReadStreamGetStatus(CFReadStreamRef stream
) {
911 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID
, CFStreamStatus
, (NSInputStream
*)stream
, streamStatus
);
912 return _CFStreamGetStatus((struct _CFStream
*)stream
);
915 CF_EXPORT CFStreamStatus
CFWriteStreamGetStatus(CFWriteStreamRef stream
) {
916 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID
, CFStreamStatus
, (NSOutputStream
*)stream
, streamStatus
);
917 return _CFStreamGetStatus((struct _CFStream
*)stream
);
920 static CFStreamError
_CFStreamGetStreamError(struct _CFStream
*stream
) {
921 CFStreamError result
;
922 if (!stream
->error
) {
925 } else if (_CFStreamGetCallBackPtr(stream
)->version
< 2) {
926 CFStreamError
*streamError
= (CFStreamError
*)(stream
->error
);
927 result
.error
= streamError
->error
;
928 result
.domain
= streamError
->domain
;
930 result
= _CFStreamErrorFromError(stream
->error
);
935 CF_EXPORT CFStreamError
CFReadStreamGetError(CFReadStreamRef stream
) {
936 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID
, CFStreamError
, (NSInputStream
*)stream
, _cfStreamError
);
937 return _CFStreamGetStreamError((struct _CFStream
*)stream
);
940 CF_EXPORT CFStreamError
CFWriteStreamGetError(CFWriteStreamRef stream
) {
941 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID
, CFStreamError
, (NSOutputStream
*)stream
, _cfStreamError
);
942 return _CFStreamGetStreamError((struct _CFStream
*)stream
);
945 static CFErrorRef
_CFStreamCopyError(struct _CFStream
*stream
) {
946 if (!stream
->error
) {
948 } else if (_CFStreamGetCallBackPtr(stream
)->version
< 2) {
949 return _CFErrorFromStreamError(CFGetAllocator(stream
), (CFStreamError
*)(stream
->error
));
951 CFRetain(stream
->error
);
952 return stream
->error
;
956 CF_EXPORT CFErrorRef
CFReadStreamCopyError(CFReadStreamRef stream
) {
957 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID
, CFErrorRef
, (NSInputStream
*)stream
, streamError
);
958 return _CFStreamCopyError((struct _CFStream
*)stream
);
961 CF_EXPORT CFErrorRef
CFWriteStreamCopyError(CFWriteStreamRef stream
) {
962 return _CFStreamCopyError((struct _CFStream
*)stream
);
963 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID
, CFErrorRef
, (NSOutputStream
*)stream
, streamError
);
966 CF_PRIVATE Boolean
_CFStreamOpen(struct _CFStream
*stream
) {
967 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
968 Boolean success
, openComplete
;
969 if (_CFStreamGetStatus(stream
) != kCFStreamStatusNotOpen
) {
972 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
973 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpening
);
975 if (cb
->version
< 2) {
976 CFStreamError err
= {0, 0};
977 success
= ((_CFStreamCBOpenV1
)(cb
->open
))(stream
, &err
, &openComplete
, _CFStreamGetInfoPointer(stream
));
978 if (err
.error
!= 0) _CFStreamSetStreamError(stream
, &err
);
980 success
= cb
->open(stream
, &(stream
->error
), &openComplete
, _CFStreamGetInfoPointer(stream
));
988 // 2957690 - Guard against the possibility that the stream has already signalled itself in to a later state (like AtEnd)
989 if (__CFStreamGetStatus(stream
) == kCFStreamStatusOpening
) {
990 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
992 _CFStreamScheduleEvent(stream
, kCFStreamEventOpenCompleted
);
994 #if DEPLOYMENT_TARGET_WINDOWS
995 _CFStreamClose(stream
);
997 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
998 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
1001 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1005 CF_EXPORT Boolean
CFReadStreamOpen(CFReadStreamRef stream
) {
1006 if(CF_IS_OBJC(__kCFReadStreamTypeID
, stream
)) {
1007 (void)CF_OBJC_CALLV((NSInputStream
*)stream
, open
);
1010 return _CFStreamOpen((struct _CFStream
*)stream
);
1013 CF_EXPORT Boolean
CFWriteStreamOpen(CFWriteStreamRef stream
) {
1014 if(CF_IS_OBJC(__kCFWriteStreamTypeID
, stream
)) {
1015 (void)CF_OBJC_CALLV((NSOutputStream
*)stream
, open
);
1018 return _CFStreamOpen((struct _CFStream
*)stream
);
1021 CF_EXPORT
void CFReadStreamClose(CFReadStreamRef stream
) {
1022 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID
, void, (NSInputStream
*)stream
, close
);
1023 _CFStreamClose((struct _CFStream
*)stream
);
1026 CF_EXPORT
void CFWriteStreamClose(CFWriteStreamRef stream
) {
1027 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID
, void, (NSOutputStream
*)stream
, close
);
1028 _CFStreamClose((struct _CFStream
*)stream
);
1031 CF_EXPORT Boolean
CFReadStreamHasBytesAvailable(CFReadStreamRef readStream
) {
1032 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID
, Boolean
, (NSInputStream
*)readStream
, hasBytesAvailable
);
1033 struct _CFStream
*stream
= (struct _CFStream
*)readStream
;
1034 CFStreamStatus status
= _CFStreamGetStatus(stream
);
1035 const struct _CFStreamCallBacks
*cb
;
1036 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusReading
) {
1039 cb
= _CFStreamGetCallBackPtr(stream
);
1040 if (cb
->canRead
== NULL
) {
1041 return TRUE
; // No way to know without trying....
1044 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1045 if (cb
->version
< 2) {
1046 result
= ((_CFStreamCBCanReadV1
)(cb
->canRead
))((CFReadStreamRef
)stream
, _CFStreamGetInfoPointer(stream
));
1048 result
= cb
->canRead((CFReadStreamRef
)stream
, &(stream
->error
), _CFStreamGetInfoPointer(stream
));
1049 if (stream
->error
) {
1050 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
1051 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
1054 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1059 static void waitForOpen(struct _CFStream
*stream
);
1060 CFIndex
CFReadStreamRead(CFReadStreamRef readStream
, UInt8
*buffer
, CFIndex bufferLength
) {
1061 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID
, CFIndex
, (NSInputStream
*)readStream
, read
:(uint8_t *)buffer maxLength
:(NSUInteger
)bufferLength
);
1062 struct _CFStream
*stream
= (struct _CFStream
*)readStream
;
1063 CFStreamStatus status
= _CFStreamGetStatus(stream
);
1064 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1065 if (status
== kCFStreamStatusOpening
) {
1066 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1067 waitForOpen(stream
);
1068 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1069 status
= _CFStreamGetStatus(stream
);
1072 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusReading
&& status
!= kCFStreamStatusAtEnd
) {
1074 } else if (status
== kCFStreamStatusAtEnd
) {
1079 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1080 if (stream
->client
) {
1081 stream
->client
->whatToSignal
&= ~kCFStreamEventHasBytesAvailable
;
1083 _CFStreamSetStatusCode(stream
, kCFStreamStatusReading
);
1084 if (cb
->version
< 2) {
1085 CFStreamError err
= {0, 0};
1086 bytesRead
= ((_CFStreamCBReadV1
)(cb
->read
))((CFReadStreamRef
)stream
, buffer
, bufferLength
, &err
, &atEOF
, _CFStreamGetInfoPointer(stream
));
1087 if (err
.error
!= 0) _CFStreamSetStreamError(stream
, &err
);
1089 bytesRead
= cb
->read((CFReadStreamRef
)stream
, buffer
, bufferLength
, &(stream
->error
), &atEOF
, _CFStreamGetInfoPointer(stream
));
1091 if (stream
->error
) {
1093 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
1094 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
1096 _CFStreamSetStatusCode(stream
, kCFStreamStatusAtEnd
);
1097 _CFStreamScheduleEvent(stream
, kCFStreamEventEndEncountered
);
1099 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
1101 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1106 CF_EXPORT
const UInt8
*CFReadStreamGetBuffer(CFReadStreamRef readStream
, CFIndex maxBytesToRead
, CFIndex
*numBytesRead
) {
1107 if (CF_IS_OBJC(__kCFReadStreamTypeID
, readStream
)) {
1108 uint8_t *bufPtr
= NULL
;
1109 Boolean gotBytes
= (Boolean
) CF_OBJC_CALLV((NSInputStream
*)readStream
, getBuffer
:&bufPtr length
:(NSUInteger
*)numBytesRead
);
1111 return (const UInt8
*)bufPtr
;
1116 struct _CFStream
*stream
= (struct _CFStream
*)readStream
;
1117 CFStreamStatus status
= _CFStreamGetStatus(stream
);
1118 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1119 const UInt8
*buffer
;
1120 if (status
== kCFStreamStatusOpening
) {
1121 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1122 waitForOpen(stream
);
1123 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1124 status
= _CFStreamGetStatus(stream
);
1126 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusReading
&& status
!= kCFStreamStatusAtEnd
) {
1129 } else if (status
== kCFStreamStatusAtEnd
|| cb
->getBuffer
== NULL
) {
1134 Boolean hadBytes
= stream
->client
&& (stream
->client
->whatToSignal
& kCFStreamEventHasBytesAvailable
);
1135 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1137 stream
->client
->whatToSignal
&= ~kCFStreamEventHasBytesAvailable
;
1139 _CFStreamSetStatusCode(stream
, kCFStreamStatusReading
);
1140 if (cb
->version
< 2) {
1141 CFStreamError err
= {0, 0};
1142 buffer
= ((_CFStreamCBGetBufferV1
)(cb
->getBuffer
))((CFReadStreamRef
)stream
, maxBytesToRead
, numBytesRead
, &err
, &atEOF
, _CFStreamGetInfoPointer(stream
));
1143 if (err
.error
!= 0) _CFStreamSetStreamError(stream
, &err
);
1145 buffer
= cb
->getBuffer((CFReadStreamRef
)stream
, maxBytesToRead
, numBytesRead
, &(stream
->error
), &atEOF
, _CFStreamGetInfoPointer(stream
));
1147 if (stream
->error
) {
1149 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
1151 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
1153 _CFStreamSetStatusCode(stream
, kCFStreamStatusAtEnd
);
1154 _CFStreamScheduleEvent(stream
, kCFStreamEventEndEncountered
);
1156 if (!buffer
&& hadBytes
) {
1157 stream
->client
->whatToSignal
|= kCFStreamEventHasBytesAvailable
;
1159 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
1161 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1166 CF_EXPORT Boolean
CFWriteStreamCanAcceptBytes(CFWriteStreamRef writeStream
) {
1167 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID
, Boolean
, (NSOutputStream
*)writeStream
, hasSpaceAvailable
);
1168 struct _CFStream
*stream
= (struct _CFStream
*)writeStream
;
1169 CFStreamStatus status
= _CFStreamGetStatus(stream
);
1170 const struct _CFStreamCallBacks
*cb
;
1171 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusWriting
) {
1174 cb
= _CFStreamGetCallBackPtr(stream
);
1175 if (cb
->canWrite
== NULL
) {
1176 return TRUE
; // No way to know without trying....
1179 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1180 if (cb
->version
< 2) {
1181 result
= ((_CFStreamCBCanWriteV1
)(cb
->canWrite
))((CFWriteStreamRef
)stream
, _CFStreamGetInfoPointer(stream
));
1183 result
= cb
->canWrite((CFWriteStreamRef
)stream
, &(stream
->error
), _CFStreamGetInfoPointer(stream
));
1184 if (stream
->error
) {
1185 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
1186 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
1189 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1194 CF_EXPORT CFIndex
CFWriteStreamWrite(CFWriteStreamRef writeStream
, const UInt8
*buffer
, CFIndex bufferLength
) {
1195 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID
, CFIndex
, (NSOutputStream
*)writeStream
, write
:(const uint8_t *)buffer maxLength
:(NSUInteger
)bufferLength
);
1196 struct _CFStream
*stream
= (struct _CFStream
*)writeStream
;
1197 CFStreamStatus status
= _CFStreamGetStatus(stream
);
1198 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1199 if (status
== kCFStreamStatusOpening
) {
1200 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1201 waitForOpen(stream
);
1202 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1203 status
= _CFStreamGetStatus(stream
);
1205 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusWriting
) {
1209 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1210 _CFStreamSetStatusCode(stream
, kCFStreamStatusWriting
);
1211 if (stream
->client
) {
1212 stream
->client
->whatToSignal
&= ~kCFStreamEventCanAcceptBytes
;
1214 if (cb
->version
< 2) {
1215 CFStreamError err
= {0, 0};
1216 result
= ((_CFStreamCBWriteV1
)(cb
->write
))((CFWriteStreamRef
)stream
, buffer
, bufferLength
, &err
, _CFStreamGetInfoPointer(stream
));
1217 if (err
.error
) _CFStreamSetStreamError(stream
, &err
);
1219 result
= cb
->write((CFWriteStreamRef
)stream
, buffer
, bufferLength
, &(stream
->error
), _CFStreamGetInfoPointer(stream
));
1221 if (stream
->error
) {
1222 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
1223 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
1224 } else if (result
== 0) {
1225 _CFStreamSetStatusCode(stream
, kCFStreamStatusAtEnd
);
1226 _CFStreamScheduleEvent(stream
, kCFStreamEventEndEncountered
);
1228 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
1230 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1235 CF_PRIVATE CFTypeRef
_CFStreamCopyProperty(struct _CFStream
*stream
, CFStringRef propertyName
) {
1236 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1237 if (cb
->copyProperty
== NULL
) {
1241 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1242 result
= cb
->copyProperty(stream
, propertyName
, _CFStreamGetInfoPointer(stream
));
1243 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1248 CF_EXPORT CFTypeRef
CFReadStreamCopyProperty(CFReadStreamRef stream
, CFStringRef propertyName
) {
1249 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID
, CFTypeRef
, (NSInputStream
*)stream
, propertyForKey
:(NSString
*)propertyName
);
1250 return _CFStreamCopyProperty((struct _CFStream
*)stream
, propertyName
);
1253 CF_EXPORT CFTypeRef
CFWriteStreamCopyProperty(CFWriteStreamRef stream
, CFStringRef propertyName
) {
1254 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID
, CFTypeRef
, (NSOutputStream
*)stream
, propertyForKey
:(NSString
*)propertyName
);
1255 return _CFStreamCopyProperty((struct _CFStream
*)stream
, propertyName
);
1258 CF_PRIVATE Boolean
_CFStreamSetProperty(struct _CFStream
*stream
, CFStringRef prop
, CFTypeRef val
) {
1259 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1260 if (cb
->setProperty
== NULL
) {
1264 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1265 result
= cb
->setProperty(stream
, prop
, val
, _CFStreamGetInfoPointer(stream
));
1266 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1272 Boolean
CFReadStreamSetProperty(CFReadStreamRef stream
, CFStringRef propertyName
, CFTypeRef propertyValue
) {
1273 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID
, Boolean
, (NSInputStream
*)stream
, setProperty
:(id
)propertyValue forKey
:(NSString
*)propertyName
);
1274 return _CFStreamSetProperty((struct _CFStream
*)stream
, propertyName
, propertyValue
);
1278 Boolean
CFWriteStreamSetProperty(CFWriteStreamRef stream
, CFStringRef propertyName
, CFTypeRef propertyValue
) {
1279 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID
, Boolean
, (NSOutputStream
*)stream
, setProperty
:(id
)propertyValue forKey
:(NSString
*)propertyName
);
1280 return _CFStreamSetProperty((struct _CFStream
*)stream
, propertyName
, propertyValue
);
1283 static void _initializeClient(struct _CFStream
*stream
) {
1284 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1285 if (!cb
->schedule
) return; // Do we wish to allow this?
1286 stream
->client
= (struct _CFStreamClient
*)CFAllocatorAllocate(CFGetAllocator(stream
), sizeof(struct _CFStreamClient
), 0);
1287 memset(stream
->client
, 0, sizeof(struct _CFStreamClient
));
1290 /* If we add a setClient callback to the concrete stream callbacks, we must set/clear CALLING_CLIENT around it */
1291 CF_PRIVATE Boolean
_CFStreamSetClient(struct _CFStream
*stream
, CFOptionFlags streamEvents
, void (*clientCB
)(struct _CFStream
*, CFStreamEventType
, void *), CFStreamClientContext
*clientCallBackContext
) {
1293 Boolean removingClient
= (streamEvents
== kCFStreamEventNone
|| clientCB
== NULL
|| clientCallBackContext
== NULL
);
1295 if (removingClient
) {
1297 streamEvents
= kCFStreamEventNone
;
1298 clientCallBackContext
= NULL
;
1300 if (!stream
->client
) {
1301 if (removingClient
) {
1302 // We have no client now, and we've been asked to add none???
1305 _initializeClient(stream
);
1306 if (!stream
->client
) {
1307 // Asynch not supported
1311 if (stream
->client
->cb
&& stream
->client
->cbContext
.release
) {
1312 stream
->client
->cbContext
.release(stream
->client
->cbContext
.info
);
1314 stream
->client
->cb
= clientCB
;
1315 if (clientCallBackContext
) {
1316 stream
->client
->cbContext
.version
= clientCallBackContext
->version
;
1317 stream
->client
->cbContext
.retain
= clientCallBackContext
->retain
;
1318 stream
->client
->cbContext
.release
= clientCallBackContext
->release
;
1319 stream
->client
->cbContext
.copyDescription
= clientCallBackContext
->copyDescription
;
1320 stream
->client
->cbContext
.info
= (clientCallBackContext
->retain
&& clientCallBackContext
->info
) ? clientCallBackContext
->retain(clientCallBackContext
->info
) : clientCallBackContext
->info
;
1322 stream
->client
->cbContext
.retain
= NULL
;
1323 stream
->client
->cbContext
.release
= NULL
;
1324 stream
->client
->cbContext
.copyDescription
= NULL
;
1325 stream
->client
->cbContext
.info
= NULL
;
1327 if (stream
->client
->when
!= streamEvents
) {
1328 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1329 stream
->client
->when
= streamEvents
;
1330 if (cb
->requestEvents
) {
1331 cb
->requestEvents(stream
, streamEvents
, _CFStreamGetInfoPointer(stream
));
1337 CF_EXPORT Boolean
CFReadStreamSetClient(CFReadStreamRef readStream
, CFOptionFlags streamEvents
, CFReadStreamClientCallBack clientCB
, CFStreamClientContext
*clientContext
) {
1338 #if defined(CFSTREAM_SUPPORTS_BRIDGING)
1339 if (CF_IS_OBJC(__kCFReadStreamTypeID
, (const void *)(NSInputStream
*)readStream
)) {
1340 NSInputStream
* is
= (NSInputStream
*) readStream
;
1342 if ([is respondsToSelector
:@
selector(_setCFClientFlags
:callback
:context
:)])
1343 return [is _setCFClientFlags
:streamEvents callback
:clientCB context
:clientContext
];
1345 if (clientCB
== NULL
)
1346 [is setDelegate
:nil
];
1348 _CFStreamDelegate
* d
= [[_CFStreamDelegate alloc
] initWithStreamEvents
:streamEvents callback
:(void*) clientCB context
:clientContext
];
1356 streamEvents
&= ~kCFStreamEventCanAcceptBytes
;
1357 return _CFStreamSetClient((struct _CFStream
*)readStream
, streamEvents
, (void (*)(struct _CFStream
*, CFStreamEventType
, void *))clientCB
, clientContext
);
1360 CF_EXPORT Boolean
CFWriteStreamSetClient(CFWriteStreamRef writeStream
, CFOptionFlags streamEvents
, CFWriteStreamClientCallBack clientCB
, CFStreamClientContext
*clientContext
) {
1361 #if defined(CFSTREAM_SUPPORTS_BRIDGING)
1362 if (CF_IS_OBJC(__kCFWriteStreamTypeID
, (const void *)(NSInputStream
*)writeStream
)) {
1363 NSOutputStream
* os
= (NSOutputStream
*) writeStream
;
1365 if ([os respondsToSelector
:@
selector(_setCFClientFlags
:callback
:context
:)])
1366 return [os _setCFClientFlags
:streamEvents callback
:clientCB context
:clientContext
];
1368 if (clientCB
== NULL
)
1369 [os setDelegate
:nil
];
1371 _CFStreamDelegate
* d
= [[_CFStreamDelegate alloc
] initWithStreamEvents
:streamEvents callback
:(void*) clientCB context
:clientContext
];
1379 streamEvents
&= ~kCFStreamEventHasBytesAvailable
;
1380 return _CFStreamSetClient((struct _CFStream
*)writeStream
, streamEvents
, (void (*)(struct _CFStream
*, CFStreamEventType
, void *))clientCB
, clientContext
);
1383 CF_INLINE
void *_CFStreamGetClient(struct _CFStream
*stream
) {
1384 if (stream
->client
) return stream
->client
->cbContext
.info
;
1388 CF_EXPORT
void *_CFReadStreamGetClient(CFReadStreamRef readStream
) {
1389 return _CFStreamGetClient((struct _CFStream
*)readStream
);
1392 CF_EXPORT
void *_CFWriteStreamGetClient(CFWriteStreamRef writeStream
) {
1393 return _CFStreamGetClient((struct _CFStream
*)writeStream
);
1397 CF_PRIVATE
void _CFStreamScheduleWithRunLoop(struct _CFStream
*stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1398 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1400 if (! stream
->client
) {
1401 _initializeClient(stream
);
1402 if (!stream
->client
) return; // we don't support asynch.
1405 if (! stream
->client
->rlSource
) {
1406 /* No source, so we join the shared source group */
1407 CFTypeRef a
[] = { runLoop
, runLoopMode
};
1409 CFArrayRef runLoopAndSourceKey
= CFArrayCreate(kCFAllocatorSystemDefault
, a
, sizeof(a
) / sizeof(a
[0]), &kCFTypeArrayCallBacks
);
1411 __CFSpinLock(&sSourceLock
);
1413 if (!sSharedSources
)
1414 sSharedSources
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1416 CFMutableArrayRef listOfStreamsSharingASource
= (CFMutableArrayRef
)CFDictionaryGetValue(sSharedSources
, runLoopAndSourceKey
);
1417 if (listOfStreamsSharingASource
) {
1418 struct _CFStream
* aStream
= (struct _CFStream
*) CFArrayGetValueAtIndex(listOfStreamsSharingASource
, 0);
1419 CFRunLoopSourceRef source
= _CFStreamCopySource(aStream
);
1421 _CFStreamSetSource(stream
, source
, FALSE
);
1424 CFRetain(listOfStreamsSharingASource
);
1427 CFRunLoopSourceContext ctxt
= {
1432 (CFStringRef(*)(const void *))CFCopyDescription
,
1437 (void(*)(void *))_cfstream_shared_signalEventSync
1440 listOfStreamsSharingASource
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
1441 CFDictionaryAddValue(sSharedSources
, runLoopAndSourceKey
, listOfStreamsSharingASource
);
1443 ctxt
.info
= listOfStreamsSharingASource
;
1445 CFRunLoopSourceRef source
= CFRunLoopSourceCreate(kCFAllocatorSystemDefault
, 0, &ctxt
);
1446 _CFStreamSetSource(stream
, source
, FALSE
);
1447 CFRunLoopAddSource(runLoop
, source
, runLoopMode
);
1451 CFArrayAppendValue(listOfStreamsSharingASource
, stream
);
1452 CFDictionaryAddValue(sSharedSources
, stream
, runLoopAndSourceKey
);
1454 CFRelease(runLoopAndSourceKey
);
1455 CFRelease(listOfStreamsSharingASource
);
1457 __CFBitSet(stream
->flags
, SHARED_SOURCE
);
1459 __CFSpinUnlock(&sSourceLock
);
1461 else if (__CFBitIsSet(stream
->flags
, SHARED_SOURCE
)) {
1462 /* We were sharing, but now we'll get our own source */
1464 CFArrayRef runLoopAndSourceKey
;
1465 CFMutableArrayRef listOfStreamsSharingASource
;
1468 CFAllocatorRef alloc
= CFGetAllocator(stream
);
1469 CFRunLoopSourceContext ctxt
= {
1472 NULL
, // Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop
1473 NULL
, // Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop
1474 (CFStringRef(*)(const void *))CFCopyDescription
,
1479 (void(*)(void *))_cfstream_solo_signalEventSync
1482 __CFSpinLock(&sSourceLock
);
1484 runLoopAndSourceKey
= (CFArrayRef
)CFRetain((CFTypeRef
)CFDictionaryGetValue(sSharedSources
, stream
));
1485 listOfStreamsSharingASource
= (CFMutableArrayRef
)CFDictionaryGetValue(sSharedSources
, runLoopAndSourceKey
);
1487 count
= CFArrayGetCount(listOfStreamsSharingASource
);
1488 i
= CFArrayGetFirstIndexOfValue(listOfStreamsSharingASource
, CFRangeMake(0, count
), stream
);
1489 if (i
!= kCFNotFound
) {
1490 CFArrayRemoveValueAtIndex(listOfStreamsSharingASource
, i
);
1495 CFRunLoopSourceRef source
= _CFStreamCopySource(stream
);
1497 CFRunLoopRemoveSource((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoopAndSourceKey
, 0), source
, (CFStringRef
)CFArrayGetValueAtIndex(runLoopAndSourceKey
, 1));
1500 CFDictionaryRemoveValue(sSharedSources
, runLoopAndSourceKey
);
1503 CFDictionaryRemoveValue(sSharedSources
, stream
);
1505 _CFStreamSetSource(stream
, NULL
, count
== 0);
1507 __CFBitClear(stream
->flags
, SHARED_SOURCE
);
1509 __CFSpinUnlock(&sSourceLock
);
1511 CFRunLoopSourceRef source
= CFRunLoopSourceCreate(alloc
, 0, &ctxt
);
1512 _CFStreamSetSource(stream
, source
, FALSE
);
1513 CFRunLoopAddSource((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoopAndSourceKey
, 0), source
, (CFStringRef
)CFArrayGetValueAtIndex(runLoopAndSourceKey
, 1));
1514 CFRelease(runLoopAndSourceKey
);
1516 CFRunLoopAddSource(runLoop
, source
, runLoopMode
);
1520 /* We're not sharing, so just add the source to the rl & mode */
1521 CFRunLoopSourceRef source
= _CFStreamCopySource(stream
);
1523 CFRunLoopAddSource(runLoop
, source
, runLoopMode
);
1528 _CFStreamLock(stream
);
1529 if (!stream
->client
->runLoopsAndModes
) {
1530 stream
->client
->runLoopsAndModes
= CFArrayCreateMutable(CFGetAllocator(stream
), 0, &kCFTypeArrayCallBacks
);
1532 CFArrayAppendValue(stream
->client
->runLoopsAndModes
, runLoop
);
1533 CFArrayAppendValue(stream
->client
->runLoopsAndModes
, runLoopMode
);
1534 checkRLMArray(stream
->client
->runLoopsAndModes
);
1535 _CFStreamUnlock(stream
);
1538 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1539 cb
->schedule(stream
, runLoop
, runLoopMode
, _CFStreamGetInfoPointer(stream
));
1540 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1544 * If we've got events pending, we need to wake up and signal
1546 if (stream
->client
&& stream
->client
->whatToSignal
!= 0) {
1547 CFRunLoopSourceRef source
= _CFStreamCopySource(stream
);
1549 CFRunLoopSourceSignal(source
);
1551 _wakeUpRunLoop(stream
);
1556 CF_EXPORT
void CFReadStreamScheduleWithRunLoop(CFReadStreamRef stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1557 #if defined(CFSTREAM_SUPPORTS_BRIDGING)
1558 if (CF_IS_OBJC(__kCFReadStreamTypeID
, (const void *)(NSInputStream
*)stream
)) {
1559 NSInputStream
* is
= (NSInputStream
*) stream
;
1560 if ([is respondsToSelector
:@
selector(_scheduleInCFRunLoop
:forMode
:)])
1561 [is _scheduleInCFRunLoop
:runLoop forMode
:runLoopMode
];
1563 [is scheduleInRunLoop
:cfToNSRL(runLoop
) forMode
:(id
) runLoopMode
];
1568 _CFStreamScheduleWithRunLoop((struct _CFStream
*)stream
, runLoop
, runLoopMode
);
1571 CF_EXPORT
void CFWriteStreamScheduleWithRunLoop(CFWriteStreamRef stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1572 #if defined(CFSTREAM_SUPPORTS_BRIDGING)
1573 if (CF_IS_OBJC(__kCFWriteStreamTypeID
, (const void *)(NSOutputStream
*)stream
)) {
1574 NSOutputStream
* os
= (NSOutputStream
*) stream
;
1575 if ([os respondsToSelector
:@
selector(_scheduleInCFRunLoop
:forMode
:)])
1576 [os _scheduleInCFRunLoop
:runLoop forMode
:runLoopMode
];
1578 [os scheduleInRunLoop
:cfToNSRL(runLoop
) forMode
:(id
) runLoopMode
];
1583 _CFStreamScheduleWithRunLoop((struct _CFStream
*)stream
, runLoop
, runLoopMode
);
1587 CF_PRIVATE
void _CFStreamUnscheduleFromRunLoop(struct _CFStream
*stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1588 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1589 if (!stream
->client
) return;
1590 if (!stream
->client
->rlSource
) return;
1592 if (!__CFBitIsSet(stream
->flags
, SHARED_SOURCE
)) {
1593 CFRunLoopSourceRef source
= _CFStreamCopySource(stream
);
1595 CFRunLoopRemoveSource(runLoop
, source
, runLoopMode
);
1599 CFArrayRef runLoopAndSourceKey
;
1600 CFMutableArrayRef list
;
1603 __CFSpinLock(&sSourceLock
);
1605 runLoopAndSourceKey
= (CFArrayRef
)CFDictionaryGetValue(sSharedSources
, stream
);
1606 list
= (CFMutableArrayRef
)CFDictionaryGetValue(sSharedSources
, runLoopAndSourceKey
);
1608 count
= CFArrayGetCount(list
);
1609 i
= CFArrayGetFirstIndexOfValue(list
, CFRangeMake(0, count
), stream
);
1610 if (i
!= kCFNotFound
) {
1611 CFArrayRemoveValueAtIndex(list
, i
);
1616 CFRunLoopSourceRef source
= _CFStreamCopySource(stream
);
1618 CFRunLoopRemoveSource(runLoop
, source
, runLoopMode
);
1621 CFDictionaryRemoveValue(sSharedSources
, runLoopAndSourceKey
);
1624 CFDictionaryRemoveValue(sSharedSources
, stream
);
1626 _CFStreamSetSource(stream
, NULL
, count
== 0);
1628 __CFBitClear(stream
->flags
, SHARED_SOURCE
);
1630 __CFSpinUnlock(&sSourceLock
);
1633 _CFStreamLock(stream
);
1634 _CFStreamRemoveRunLoopAndModeFromArray(stream
->client
->runLoopsAndModes
, runLoop
, runLoopMode
);
1635 checkRLMArray(stream
->client
->runLoopsAndModes
);
1636 _CFStreamUnlock(stream
);
1638 if (cb
->unschedule
) {
1639 cb
->unschedule(stream
, runLoop
, runLoopMode
, _CFStreamGetInfoPointer(stream
));
1643 CF_EXPORT
void CFReadStreamUnscheduleFromRunLoop(CFReadStreamRef stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1644 #if defined(CFSTREAM_SUPPORTS_BRIDGING)
1645 if (CF_IS_OBJC(__kCFReadStreamTypeID
, (const void *)(NSInputStream
*)stream
)) {
1646 NSInputStream
* is
= (NSInputStream
*) stream
;
1647 if ([is respondsToSelector
:@
selector(_unscheduleFromCFRunLoop
:forMode
:)])
1648 [is _unscheduleFromCFRunLoop
:runLoop forMode
:runLoopMode
];
1650 [is removeFromRunLoop
:cfToNSRL(runLoop
) forMode
:(id
) runLoopMode
];
1655 _CFStreamUnscheduleFromRunLoop((struct _CFStream
*)stream
, runLoop
, runLoopMode
);
1658 void CFWriteStreamUnscheduleFromRunLoop(CFWriteStreamRef stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1659 #if defined(CFSTREAM_SUPPORTS_BRIDGING)
1660 if (CF_IS_OBJC(__kCFWriteStreamTypeID
, (const void *)(NSOutputStream
*)stream
)) {
1661 NSOutputStream
* os
= (NSOutputStream
*) stream
;
1662 if ([os respondsToSelector
:@
selector(_unscheduleFromCFRunLoop
:forMode
:)])
1663 [os _unscheduleFromCFRunLoop
:runLoop forMode
:runLoopMode
];
1665 [os removeFromRunLoop
:cfToNSRL(runLoop
) forMode
:(id
) runLoopMode
];
1670 _CFStreamUnscheduleFromRunLoop((struct _CFStream
*)stream
, runLoop
, runLoopMode
);
1673 static CFRunLoopRef sLegacyRL
= NULL
;
1675 static void _perform(void* info
)
1679 static void* _legacyStreamRunLoop_workThread(void* arg
)
1681 sLegacyRL
= CFRunLoopGetCurrent();
1683 #if defined(LOG_STREAM)
1684 fprintf(stderr
, "Creating Schedulingset emulation thread. Runloop: %p\n", sLegacyRL
);
1687 CFStringRef s
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("<< CFStreamLegacySource for Runloop %p >>"), sLegacyRL
);
1689 CFRunLoopSourceContext ctxt
= {
1702 CFRunLoopSourceRef rls
= CFRunLoopSourceCreate(kCFAllocatorDefault
, 0, &ctxt
);
1705 CFRunLoopAddSource(sLegacyRL
, rls
, kCFRunLoopDefaultMode
);
1708 dispatch_semaphore_signal(*(dispatch_semaphore_t
*) arg
);
1712 SInt32 why
= CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 1E30
, true);
1715 #if defined(LOG_STREAM)
1717 case kCFRunLoopRunFinished
:
1718 fprintf(stderr
, "WOKE: kCFRunLoopRunFinished\n");
1720 case kCFRunLoopRunStopped
:
1721 fprintf(stderr
, "WOKE: kCFRunLoopRunStopped\n");
1723 case kCFRunLoopRunTimedOut
:
1724 fprintf(stderr
, "WOKE: kCFRunLoopRunTimedOut\n");
1726 case kCFRunLoopRunHandledSource
:
1727 fprintf(stderr
, "WOKE: kCFRunLoopRunHandledSource\n");
1735 static CFRunLoopRef
_legacyStreamRunLoop()
1737 static dispatch_once_t sOnce
= 0;
1739 dispatch_once(&sOnce
, ^{
1741 if (sLegacyRL
== NULL
) {
1742 dispatch_semaphore_t sem
= dispatch_semaphore_create(0);
1744 pthread_attr_t attr
;
1745 pthread_attr_init(&attr
);
1746 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
1747 pthread_t workThread
;
1748 (void) pthread_create(&workThread
, &attr
, _legacyStreamRunLoop_workThread
, &sem
);
1749 pthread_attr_destroy(&attr
);
1751 dispatch_semaphore_wait(sem
, DISPATCH_TIME_FOREVER
);
1752 dispatch_release(sem
);
1759 static dispatch_queue_t
_CFStreamCopyDispatchQueue(struct _CFStream
* stream
)
1761 dispatch_queue_t result
= NULL
;
1763 _CFStreamLock(stream
);
1764 if (stream
->client
) {
1765 result
= stream
->queue
;
1767 dispatch_retain(result
);
1769 _CFStreamUnlock(stream
);
1774 static void _CFStreamSetDispatchQueue(struct _CFStream
* stream
, dispatch_queue_t q
)
1776 CFArrayRef rlm
= _CFStreamCopyRunLoopsAndModes(stream
);
1778 CFIndex count
= CFArrayGetCount(rlm
);
1779 for (CFIndex i
= 0; i
< count
; i
+= 2) {
1780 CFRunLoopRef rl
= (CFRunLoopRef
) CFArrayGetValueAtIndex(rlm
, i
);
1781 CFStringRef mode
= (CFStringRef
) CFArrayGetValueAtIndex(rlm
, i
+ 1);
1782 _CFStreamUnscheduleFromRunLoop(stream
, rl
, mode
);
1788 _CFStreamLock(stream
);
1789 if (stream
->client
) {
1791 dispatch_release(stream
->queue
);
1792 stream
->queue
= NULL
;
1794 _CFStreamUnlock(stream
);
1796 _CFStreamScheduleWithRunLoop(stream
, _legacyStreamRunLoop(), kCFRunLoopDefaultMode
);
1798 _CFStreamLock(stream
);
1799 if (stream
->client
) {
1800 if (stream
->queue
!= q
) {
1802 dispatch_release(stream
->queue
);
1805 dispatch_retain(stream
->queue
);
1809 _CFStreamUnlock(stream
);
1813 void CFReadStreamSetDispatchQueue(CFReadStreamRef stream
, dispatch_queue_t q
)
1815 _CFStreamSetDispatchQueue((struct _CFStream
*) stream
, q
);
1818 void CFWriteStreamSetDispatchQueue(CFWriteStreamRef stream
, dispatch_queue_t q
)
1820 _CFStreamSetDispatchQueue((struct _CFStream
*) stream
, q
);
1823 dispatch_queue_t
CFReadStreamCopyDispatchQueue(CFReadStreamRef stream
)
1825 return _CFStreamCopyDispatchQueue((struct _CFStream
*) stream
);
1828 dispatch_queue_t
CFWriteStreamCopyDispatchQueue(CFWriteStreamRef stream
)
1830 return _CFStreamCopyDispatchQueue((struct _CFStream
*) stream
);
1834 static void waitForOpen(struct _CFStream
*stream
) {
1835 CFRunLoopRef runLoop
= CFRunLoopGetCurrent();
1836 CFStringRef privateMode
= CFSTR("_kCFStreamBlockingOpenMode");
1837 _CFStreamScheduleWithRunLoop(stream
, runLoop
, privateMode
);
1838 // We cannot call _CFStreamGetStatus, because that tries to set/clear CALLING_CLIENT, which should be set around this entire call (we're within a call from the client). This should be o.k., because we're running the run loop, so our status code should be being updated in a timely fashion....
1839 while (__CFStreamGetStatus(stream
) == kCFStreamStatusOpening
) {
1840 CFRunLoopRunInMode(privateMode
, 1e+20, TRUE
);
1842 _CFStreamUnscheduleFromRunLoop(stream
, runLoop
, privateMode
);
1845 CF_EXPORT CFArrayRef
_CFReadStreamGetRunLoopsAndModes(CFReadStreamRef readStream
) {
1846 return _CFStreamGetRunLoopsAndModes((struct _CFStream
*)readStream
);
1849 CF_EXPORT CFArrayRef
_CFWriteStreamGetRunLoopsAndModes(CFWriteStreamRef writeStream
) {
1850 return _CFStreamGetRunLoopsAndModes((struct _CFStream
*)writeStream
);
1853 CF_EXPORT CFArrayRef
_CFReadStreamCopyRunLoopsAndModes(CFReadStreamRef readStream
) {
1854 return _CFStreamCopyRunLoopsAndModes((struct _CFStream
*)readStream
);
1857 CF_EXPORT CFArrayRef
_CFWriteStreamCopyRunLoopsAndModes(CFWriteStreamRef writeStream
) {
1858 return _CFStreamCopyRunLoopsAndModes((struct _CFStream
*)writeStream
);
1861 CF_EXPORT
void CFReadStreamSignalEvent(CFReadStreamRef stream
, CFStreamEventType event
, const void *error
) {
1862 _CFStreamSignalEvent((struct _CFStream
*)stream
, event
, (CFErrorRef
)error
, TRUE
);
1865 CF_EXPORT
void CFWriteStreamSignalEvent(CFWriteStreamRef stream
, CFStreamEventType event
, const void *error
) {
1866 _CFStreamSignalEvent((struct _CFStream
*)stream
, event
, (CFErrorRef
)error
, TRUE
);
1869 CF_EXPORT
void _CFReadStreamSignalEventDelayed(CFReadStreamRef stream
, CFStreamEventType event
, const void *error
) {
1870 _CFStreamSignalEvent((struct _CFStream
*)stream
, event
, (CFErrorRef
)error
, FALSE
);
1873 CF_EXPORT
void _CFReadStreamClearEvent(CFReadStreamRef readStream
, CFStreamEventType event
) {
1874 struct _CFStream
*stream
= (struct _CFStream
*)readStream
;
1875 if (stream
->client
) {
1876 stream
->client
->whatToSignal
&= ~event
;
1880 CF_EXPORT
void _CFWriteStreamSignalEventDelayed(CFWriteStreamRef stream
, CFStreamEventType event
, const void *error
) {
1881 _CFStreamSignalEvent((struct _CFStream
*)stream
, event
, (CFErrorRef
)error
, FALSE
);
1884 CF_EXPORT
void *CFReadStreamGetInfoPointer(CFReadStreamRef stream
) {
1885 return _CFStreamGetInfoPointer((struct _CFStream
*)stream
);
1888 CF_EXPORT
void *CFWriteStreamGetInfoPointer(CFWriteStreamRef stream
) {
1889 return _CFStreamGetInfoPointer((struct _CFStream
*)stream
);
1893 void _CFStreamSourceScheduleWithRunLoop(CFRunLoopSourceRef source
, CFMutableArrayRef runLoopsAndModes
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
)
1898 checkRLMArray(runLoopsAndModes
);
1900 count
= CFArrayGetCount(runLoopsAndModes
);
1901 range
= CFRangeMake(0, count
);
1903 while (range
.length
) {
1905 CFIndex i
= CFArrayGetFirstIndexOfValue(runLoopsAndModes
, range
, runLoop
);
1907 if (i
== kCFNotFound
)
1910 if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes
, i
+ 1), runLoopMode
))
1913 range
.location
= i
+ 2;
1914 range
.length
= count
- range
.location
;
1917 // Add the new values.
1918 CFArrayAppendValue(runLoopsAndModes
, runLoop
);
1919 CFArrayAppendValue(runLoopsAndModes
, runLoopMode
);
1921 // Schedule the source on the new loop and mode.
1923 CFRunLoopAddSource(runLoop
, source
, runLoopMode
);
1928 void _CFStreamSourceUnscheduleFromRunLoop(CFRunLoopSourceRef source
, CFMutableArrayRef runLoopsAndModes
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
)
1933 count
= CFArrayGetCount(runLoopsAndModes
);
1934 range
= CFRangeMake(0, count
);
1936 checkRLMArray(runLoopsAndModes
);
1938 while (range
.length
) {
1940 CFIndex i
= CFArrayGetFirstIndexOfValue(runLoopsAndModes
, range
, runLoop
);
1942 // If not found, it's not scheduled on it.
1943 if (i
== kCFNotFound
)
1946 // Make sure it is scheduled in this mode.
1947 if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes
, i
+ 1), runLoopMode
)) {
1949 // Remove mode and runloop from the list.
1950 CFArrayReplaceValues(runLoopsAndModes
, CFRangeMake(i
, 2), NULL
, 0);
1952 // Remove it from the runloop.
1954 CFRunLoopRemoveSource(runLoop
, source
, runLoopMode
);
1959 range
.location
= i
+ 2;
1960 range
.length
= count
- range
.location
;
1966 void _CFStreamSourceScheduleWithAllRunLoops(CFRunLoopSourceRef source
, CFArrayRef runLoopsAndModes
)
1968 CFIndex i
, count
= CFArrayGetCount(runLoopsAndModes
);
1973 checkRLMArray(runLoopsAndModes
);
1975 for (i
= 0; i
< count
; i
+= 2) {
1977 // Make sure it's scheduled on all the right loops and modes.
1978 // Go through the array adding the source to all loops and modes.
1979 CFRunLoopAddSource((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoopsAndModes
, i
),
1981 (CFStringRef
)CFArrayGetValueAtIndex(runLoopsAndModes
, i
+ 1));
1987 void _CFStreamSourceUncheduleFromAllRunLoops(CFRunLoopSourceRef source
, CFArrayRef runLoopsAndModes
)
1989 CFIndex i
, count
= CFArrayGetCount(runLoopsAndModes
);
1994 checkRLMArray(runLoopsAndModes
);
1996 for (i
= 0; i
< count
; i
+= 2) {
1998 // Go through the array removing the source from all loops and modes.
1999 CFRunLoopRemoveSource((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoopsAndModes
, i
),
2001 (CFStringRef
)CFArrayGetValueAtIndex(runLoopsAndModes
, i
+ 1));
2005 Boolean
_CFStreamRemoveRunLoopAndModeFromArray(CFMutableArrayRef runLoopsAndModes
, CFRunLoopRef rl
, CFStringRef mode
) {
2007 Boolean found
= FALSE
;
2009 if (!runLoopsAndModes
) return FALSE
;
2011 checkRLMArray(runLoopsAndModes
);
2013 cnt
= CFArrayGetCount(runLoopsAndModes
);
2014 for (idx
= 0; idx
+ 1 < cnt
; idx
+= 2) {
2015 if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes
, idx
), rl
) && CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes
, idx
+ 1), mode
)) {
2016 CFArrayRemoveValueAtIndex(runLoopsAndModes
, idx
);
2017 CFArrayRemoveValueAtIndex(runLoopsAndModes
, idx
);
2025 // Used by NSStream to properly allocate the bridged objects
2026 CF_EXPORT CFIndex
_CFStreamInstanceSize(void) {
2027 return sizeof(struct _CFStream
);
2030 #if DEPLOYMENT_TARGET_WINDOWS
2031 void __CFStreamCleanup(void) {
2032 __CFSpinLock(&sSourceLock
);
2033 if (sSharedSources
) {
2034 CFIndex count
= CFDictionaryGetCount(sSharedSources
);
2036 // Only release if empty. If it's still holding streams (which would be a client
2037 // bug leak), freeing this dict would free the streams, which then need to access the
2038 // dict to remove themselves, which leads to a deadlock.
2039 CFRelease(sSharedSources
);
2040 sSharedSources
= NULL
;
2042 const void ** keys
= (const void **)malloc(sizeof(const void *) * count
);
2046 CFDictionaryGetKeysAndValues(sSharedSources
, keys
, NULL
);
2047 fprintf(stderr
, "*** CFNetwork is shutting down, but %ld streams are still scheduled.\n", count
);
2049 for (i
= 0; i
< count
;i
++) {
2050 if ((CFGetTypeID(keys
[i
]) == __kCFReadStreamTypeID
) || (CFGetTypeID(keys
[i
]) == __kCFWriteStreamTypeID
)) {
2057 __CFSpinUnlock(&sSourceLock
);