2 * Copyright (c) 2015 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 Copyright (c) 2000-2014, 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.
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 CFLock_t sSourceLock
= CFLockInit
;
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 __CFLock(&stream
->streamLock
);
107 CF_INLINE
void _CFStreamUnlock(struct _CFStream
* stream
) {
108 __CFUnlock(&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((void *)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 __CFLock(&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 __CFUnlock(&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
, (void *)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 static dispatch_once_t initOnce
;
365 dispatch_once(&initOnce
, ^{ __kCFReadStreamTypeID
= _CFRuntimeRegisterClass(&__CFReadStreamClass
); __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
= CFLockInit
;
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 __CFLock(&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 __CFUnlock(&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 *)(NSOutputStream
*)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 __CFLock(&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 __CFUnlock(&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 __CFLock(&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 __CFUnlock(&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 __CFLock(&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 __CFUnlock(&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 pthread_setname_np("com.apple.CFStream.LegacyThread");
1682 sLegacyRL
= CFRunLoopGetCurrent();
1684 #if defined(LOG_STREAM)
1685 fprintf(stderr
, "Creating Schedulingset emulation thread. Runloop: %p\n", sLegacyRL
);
1688 CFStringRef s
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("<< CFStreamLegacySource for Runloop %p >>"), sLegacyRL
);
1690 CFRunLoopSourceContext ctxt
= {
1703 CFRunLoopSourceRef rls
= CFRunLoopSourceCreate(kCFAllocatorDefault
, 0, &ctxt
);
1706 CFRunLoopAddSource(sLegacyRL
, rls
, kCFRunLoopDefaultMode
);
1709 dispatch_semaphore_signal(*(dispatch_semaphore_t
*) arg
);
1713 SInt32 why
= CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 1E30
, true);
1716 #if defined(LOG_STREAM)
1718 case kCFRunLoopRunFinished
:
1719 fprintf(stderr
, "WOKE: kCFRunLoopRunFinished\n");
1721 case kCFRunLoopRunStopped
:
1722 fprintf(stderr
, "WOKE: kCFRunLoopRunStopped\n");
1724 case kCFRunLoopRunTimedOut
:
1725 fprintf(stderr
, "WOKE: kCFRunLoopRunTimedOut\n");
1727 case kCFRunLoopRunHandledSource
:
1728 fprintf(stderr
, "WOKE: kCFRunLoopRunHandledSource\n");
1736 static CFRunLoopRef
_legacyStreamRunLoop()
1738 static dispatch_once_t sOnce
= 0;
1740 dispatch_once(&sOnce
, ^{
1742 if (sLegacyRL
== NULL
) {
1743 dispatch_semaphore_t sem
= dispatch_semaphore_create(0);
1745 pthread_attr_t attr
;
1746 pthread_attr_init(&attr
);
1747 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
1748 pthread_attr_set_qos_class_np(&attr
, qos_class_main(), 0);
1749 pthread_t workThread
;
1750 (void) pthread_create(&workThread
, &attr
, _legacyStreamRunLoop_workThread
, &sem
);
1751 pthread_attr_destroy(&attr
);
1753 dispatch_semaphore_wait(sem
, DISPATCH_TIME_FOREVER
);
1754 dispatch_release(sem
);
1761 static dispatch_queue_t
_CFStreamCopyDispatchQueue(struct _CFStream
* stream
)
1763 dispatch_queue_t result
= NULL
;
1765 _CFStreamLock(stream
);
1766 if (stream
->client
) {
1767 result
= stream
->queue
;
1769 dispatch_retain(result
);
1771 _CFStreamUnlock(stream
);
1776 static void _CFStreamSetDispatchQueue(struct _CFStream
* stream
, dispatch_queue_t q
)
1778 CFArrayRef rlm
= _CFStreamCopyRunLoopsAndModes(stream
);
1780 CFIndex count
= CFArrayGetCount(rlm
);
1781 for (CFIndex i
= 0; i
< count
; i
+= 2) {
1782 CFRunLoopRef rl
= (CFRunLoopRef
) CFArrayGetValueAtIndex(rlm
, i
);
1783 CFStringRef mode
= (CFStringRef
) CFArrayGetValueAtIndex(rlm
, i
+ 1);
1784 _CFStreamUnscheduleFromRunLoop(stream
, rl
, mode
);
1790 _CFStreamLock(stream
);
1791 if (stream
->client
) {
1793 dispatch_release(stream
->queue
);
1794 stream
->queue
= NULL
;
1796 _CFStreamUnlock(stream
);
1798 _CFStreamScheduleWithRunLoop(stream
, _legacyStreamRunLoop(), kCFRunLoopDefaultMode
);
1800 _CFStreamLock(stream
);
1801 if (stream
->client
) {
1802 if (stream
->queue
!= q
) {
1804 dispatch_release(stream
->queue
);
1807 dispatch_retain(stream
->queue
);
1811 _CFStreamUnlock(stream
);
1815 void CFReadStreamSetDispatchQueue(CFReadStreamRef stream
, dispatch_queue_t q
)
1817 _CFStreamSetDispatchQueue((struct _CFStream
*) stream
, q
);
1820 void CFWriteStreamSetDispatchQueue(CFWriteStreamRef stream
, dispatch_queue_t q
)
1822 _CFStreamSetDispatchQueue((struct _CFStream
*) stream
, q
);
1825 dispatch_queue_t
CFReadStreamCopyDispatchQueue(CFReadStreamRef stream
)
1827 return _CFStreamCopyDispatchQueue((struct _CFStream
*) stream
);
1830 dispatch_queue_t
CFWriteStreamCopyDispatchQueue(CFWriteStreamRef stream
)
1832 return _CFStreamCopyDispatchQueue((struct _CFStream
*) stream
);
1836 static void waitForOpen(struct _CFStream
*stream
) {
1837 CFRunLoopRef runLoop
= CFRunLoopGetCurrent();
1838 CFStringRef privateMode
= CFSTR("_kCFStreamBlockingOpenMode");
1839 _CFStreamScheduleWithRunLoop(stream
, runLoop
, privateMode
);
1840 // 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....
1841 while (__CFStreamGetStatus(stream
) == kCFStreamStatusOpening
) {
1842 CFRunLoopRunInMode(privateMode
, 1e+20, TRUE
);
1844 _CFStreamUnscheduleFromRunLoop(stream
, runLoop
, privateMode
);
1847 CF_EXPORT CFArrayRef
_CFReadStreamGetRunLoopsAndModes(CFReadStreamRef readStream
) {
1848 return _CFStreamGetRunLoopsAndModes((struct _CFStream
*)readStream
);
1851 CF_EXPORT CFArrayRef
_CFWriteStreamGetRunLoopsAndModes(CFWriteStreamRef writeStream
) {
1852 return _CFStreamGetRunLoopsAndModes((struct _CFStream
*)writeStream
);
1855 CF_EXPORT CFArrayRef
_CFReadStreamCopyRunLoopsAndModes(CFReadStreamRef readStream
) {
1856 return _CFStreamCopyRunLoopsAndModes((struct _CFStream
*)readStream
);
1859 CF_EXPORT CFArrayRef
_CFWriteStreamCopyRunLoopsAndModes(CFWriteStreamRef writeStream
) {
1860 return _CFStreamCopyRunLoopsAndModes((struct _CFStream
*)writeStream
);
1863 CF_EXPORT
void CFReadStreamSignalEvent(CFReadStreamRef stream
, CFStreamEventType event
, const void *error
) {
1864 _CFStreamSignalEvent((struct _CFStream
*)stream
, event
, (CFErrorRef
)error
, TRUE
);
1867 CF_EXPORT
void CFWriteStreamSignalEvent(CFWriteStreamRef stream
, CFStreamEventType event
, const void *error
) {
1868 _CFStreamSignalEvent((struct _CFStream
*)stream
, event
, (CFErrorRef
)error
, TRUE
);
1871 CF_EXPORT
void _CFReadStreamSignalEventDelayed(CFReadStreamRef stream
, CFStreamEventType event
, const void *error
) {
1872 _CFStreamSignalEvent((struct _CFStream
*)stream
, event
, (CFErrorRef
)error
, FALSE
);
1875 CF_EXPORT
void _CFReadStreamClearEvent(CFReadStreamRef readStream
, CFStreamEventType event
) {
1876 struct _CFStream
*stream
= (struct _CFStream
*)readStream
;
1877 if (stream
->client
) {
1878 stream
->client
->whatToSignal
&= ~event
;
1882 CF_EXPORT
void _CFWriteStreamSignalEventDelayed(CFWriteStreamRef stream
, CFStreamEventType event
, const void *error
) {
1883 _CFStreamSignalEvent((struct _CFStream
*)stream
, event
, (CFErrorRef
)error
, FALSE
);
1886 CF_EXPORT
void *CFReadStreamGetInfoPointer(CFReadStreamRef stream
) {
1887 return _CFStreamGetInfoPointer((struct _CFStream
*)stream
);
1890 CF_EXPORT
void *CFWriteStreamGetInfoPointer(CFWriteStreamRef stream
) {
1891 return _CFStreamGetInfoPointer((struct _CFStream
*)stream
);
1895 void _CFStreamSourceScheduleWithRunLoop(CFRunLoopSourceRef source
, CFMutableArrayRef runLoopsAndModes
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
)
1900 checkRLMArray(runLoopsAndModes
);
1902 count
= CFArrayGetCount(runLoopsAndModes
);
1903 range
= CFRangeMake(0, count
);
1905 while (range
.length
) {
1907 CFIndex i
= CFArrayGetFirstIndexOfValue(runLoopsAndModes
, range
, runLoop
);
1909 if (i
== kCFNotFound
)
1912 if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes
, i
+ 1), runLoopMode
))
1915 range
.location
= i
+ 2;
1916 range
.length
= count
- range
.location
;
1919 // Add the new values.
1920 CFArrayAppendValue(runLoopsAndModes
, runLoop
);
1921 CFArrayAppendValue(runLoopsAndModes
, runLoopMode
);
1923 // Schedule the source on the new loop and mode.
1925 CFRunLoopAddSource(runLoop
, source
, runLoopMode
);
1930 void _CFStreamSourceUnscheduleFromRunLoop(CFRunLoopSourceRef source
, CFMutableArrayRef runLoopsAndModes
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
)
1935 count
= CFArrayGetCount(runLoopsAndModes
);
1936 range
= CFRangeMake(0, count
);
1938 checkRLMArray(runLoopsAndModes
);
1940 while (range
.length
) {
1942 CFIndex i
= CFArrayGetFirstIndexOfValue(runLoopsAndModes
, range
, runLoop
);
1944 // If not found, it's not scheduled on it.
1945 if (i
== kCFNotFound
)
1948 // Make sure it is scheduled in this mode.
1949 if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes
, i
+ 1), runLoopMode
)) {
1951 // Remove mode and runloop from the list.
1952 CFArrayReplaceValues(runLoopsAndModes
, CFRangeMake(i
, 2), NULL
, 0);
1954 // Remove it from the runloop.
1956 CFRunLoopRemoveSource(runLoop
, source
, runLoopMode
);
1961 range
.location
= i
+ 2;
1962 range
.length
= count
- range
.location
;
1968 void _CFStreamSourceScheduleWithAllRunLoops(CFRunLoopSourceRef source
, CFArrayRef runLoopsAndModes
)
1970 CFIndex i
, count
= CFArrayGetCount(runLoopsAndModes
);
1975 checkRLMArray(runLoopsAndModes
);
1977 for (i
= 0; i
< count
; i
+= 2) {
1979 // Make sure it's scheduled on all the right loops and modes.
1980 // Go through the array adding the source to all loops and modes.
1981 CFRunLoopAddSource((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoopsAndModes
, i
),
1983 (CFStringRef
)CFArrayGetValueAtIndex(runLoopsAndModes
, i
+ 1));
1989 void _CFStreamSourceUncheduleFromAllRunLoops(CFRunLoopSourceRef source
, CFArrayRef runLoopsAndModes
)
1991 CFIndex i
, count
= CFArrayGetCount(runLoopsAndModes
);
1996 checkRLMArray(runLoopsAndModes
);
1998 for (i
= 0; i
< count
; i
+= 2) {
2000 // Go through the array removing the source from all loops and modes.
2001 CFRunLoopRemoveSource((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoopsAndModes
, i
),
2003 (CFStringRef
)CFArrayGetValueAtIndex(runLoopsAndModes
, i
+ 1));
2007 Boolean
_CFStreamRemoveRunLoopAndModeFromArray(CFMutableArrayRef runLoopsAndModes
, CFRunLoopRef rl
, CFStringRef mode
) {
2009 Boolean found
= FALSE
;
2011 if (!runLoopsAndModes
) return FALSE
;
2013 checkRLMArray(runLoopsAndModes
);
2015 cnt
= CFArrayGetCount(runLoopsAndModes
);
2016 for (idx
= 0; idx
+ 1 < cnt
; idx
+= 2) {
2017 if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes
, idx
), rl
) && CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes
, idx
+ 1), mode
)) {
2018 CFArrayRemoveValueAtIndex(runLoopsAndModes
, idx
);
2019 CFArrayRemoveValueAtIndex(runLoopsAndModes
, idx
);
2027 // Used by NSStream to properly allocate the bridged objects
2028 CF_EXPORT CFIndex
_CFStreamInstanceSize(void) {
2029 return sizeof(struct _CFStream
);
2032 #if DEPLOYMENT_TARGET_WINDOWS
2033 void __CFStreamCleanup(void) {
2034 __CFLock(&sSourceLock
);
2035 if (sSharedSources
) {
2036 CFIndex count
= CFDictionaryGetCount(sSharedSources
);
2038 // Only release if empty. If it's still holding streams (which would be a client
2039 // bug leak), freeing this dict would free the streams, which then need to access the
2040 // dict to remove themselves, which leads to a deadlock.
2041 CFRelease(sSharedSources
);
2042 sSharedSources
= NULL
;
2044 const void ** keys
= (const void **)malloc(sizeof(const void *) * count
);
2048 CFDictionaryGetKeysAndValues(sSharedSources
, keys
, NULL
);
2049 fprintf(stderr
, "*** CFNetwork is shutting down, but %ld streams are still scheduled.\n", count
);
2051 for (i
= 0; i
< count
;i
++) {
2052 if ((CFGetTypeID(keys
[i
]) == __kCFReadStreamTypeID
) || (CFGetTypeID(keys
[i
]) == __kCFWriteStreamTypeID
)) {
2059 __CFUnlock(&sSourceLock
);