2 * Copyright (c) 2012 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-2012, 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"
42 CFSpinLock_t streamLock
;
43 CFArrayRef previousRunloopsAndModes
;
47 MIN_STATUS_CODE_BIT
= 0,
49 MAX_STATUS_CODE_BIT
= 4,
51 CONSTANT_CALLBACKS
= 5,
52 CALLING_CLIENT
= 6, // MUST remain 6 since it's value is used elsewhere.
56 // Values above used to be defined and others may rely on their values
58 // Values below should not matter if they are re-ordered or shift
64 /* 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
65 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 */
66 // Used in CFNetwork too
68 /* sSharesSources holds two mappings, one the inverse of the other, between a stream and the
69 RunLoop+RunLoopMode pair that it's scheduled in. If the stream is scheduled in more than
70 one loop or mode, it can't share RunLoopSources with others, and is not in this dict.
72 static CFSpinLock_t sSourceLock
= CFSpinLockInit
;
73 static CFMutableDictionaryRef sSharedSources
= NULL
;
75 static CFTypeID __kCFReadStreamTypeID
= _kCFRuntimeNotATypeID
;
76 static CFTypeID __kCFWriteStreamTypeID
= _kCFRuntimeNotATypeID
;
78 // Just reads the bits, for those cases where we don't want to go through any callback checking
79 #define __CFStreamGetStatus(x) __CFBitfieldGetValue((x)->flags, MAX_STATUS_CODE_BIT, MIN_STATUS_CODE_BIT)
81 __private_extern__ CFStreamStatus
_CFStreamGetStatus(struct _CFStream
*stream
);
82 static Boolean
_CFStreamRemoveRunLoopAndModeFromArray(CFMutableArrayRef runLoopsAndModes
, CFRunLoopRef rl
, CFStringRef mode
);
83 static void _wakeUpRunLoop(struct _CFStream
*stream
);
85 CF_INLINE
void checkRLMArray(CFArrayRef arr
)
88 assert(arr
== NULL
|| (CFArrayGetCount(arr
) % 2) == 0);
92 CF_INLINE
void* _CFStreamCreateReserved(CFAllocatorRef alloc
) {
93 struct CFStreamAux
* aux
= (struct CFStreamAux
*) CFAllocatorAllocate(alloc
, sizeof(struct CFStreamAux
), 0);
95 aux
->streamLock
= CFSpinLockInit
;
96 aux
->previousRunloopsAndModes
= NULL
;
101 CF_INLINE
void _CFStreamDestroyReserved(CFAllocatorRef alloc
, void* aux
) {
102 struct CFStreamAux
* paux
= (struct CFStreamAux
*) aux
;
103 if (paux
->previousRunloopsAndModes
)
104 CFRelease(paux
->previousRunloopsAndModes
);
105 CFAllocatorDeallocate(alloc
, aux
);
108 CF_INLINE
struct CFStreamAux
* _CFStreamGetAuxRecord(struct _CFStream
* stream
) {
109 return (struct CFStreamAux
*) stream
->_reserved1
;
112 CF_INLINE
void _CFStreamLock(struct _CFStream
* stream
) {
113 __CFSpinLock(&_CFStreamGetAuxRecord(stream
)->streamLock
);
116 CF_INLINE
void _CFStreamUnlock(struct _CFStream
* stream
) {
117 __CFSpinUnlock(&_CFStreamGetAuxRecord(stream
)->streamLock
);
120 CF_INLINE CFRunLoopSourceRef
_CFStreamCopySource(struct _CFStream
* stream
) {
121 CFRunLoopSourceRef source
= NULL
;
124 _CFStreamLock(stream
);
127 source
= stream
->client
->rlSource
;
132 _CFStreamUnlock(stream
);
138 CF_INLINE
void _CFStreamSetSource(struct _CFStream
* stream
, CFRunLoopSourceRef source
, Boolean invalidateOldSource
) {
139 CFRunLoopSourceRef oldSource
= NULL
;
142 _CFStreamLock(stream
);
143 if (stream
->client
) {
144 oldSource
= stream
->client
->rlSource
;
145 if (oldSource
!= NULL
)
148 stream
->client
->rlSource
= source
;
152 _CFStreamUnlock(stream
);
156 // Lose our extra retain
157 CFRelease(oldSource
);
159 if (invalidateOldSource
)
160 CFRunLoopSourceInvalidate(oldSource
);
162 // And lose the one that held it in our stream as well
163 CFRelease(oldSource
);
167 CF_INLINE
const struct _CFStreamCallBacks
*_CFStreamGetCallBackPtr(struct _CFStream
*stream
) {
168 return stream
->callBacks
;
171 CF_INLINE
void _CFStreamSetStatusCode(struct _CFStream
*stream
, CFStreamStatus newStatus
) {
172 CFStreamStatus status
= __CFStreamGetStatus(stream
);
173 if (((status
!= kCFStreamStatusClosed
) && (status
!= kCFStreamStatusError
)) ||
174 ((status
== kCFStreamStatusClosed
) && (newStatus
== kCFStreamStatusError
)))
176 __CFBitfieldSetValue(stream
->flags
, MAX_STATUS_CODE_BIT
, MIN_STATUS_CODE_BIT
, newStatus
);
180 CF_INLINE
void _CFStreamScheduleEvent(struct _CFStream
*stream
, CFStreamEventType event
) {
181 if (stream
->client
&& (stream
->client
->when
& event
)) {
182 CFRunLoopSourceRef source
= _CFStreamCopySource(stream
);
184 stream
->client
->whatToSignal
|= event
;
186 CFRunLoopSourceSignal(source
);
188 _wakeUpRunLoop(stream
);
193 CF_INLINE
void _CFStreamSetStreamError(struct _CFStream
*stream
, CFStreamError
*err
) {
194 if (!stream
->error
) {
195 stream
->error
= (CFErrorRef
)CFAllocatorAllocate(CFGetAllocator(stream
), sizeof(CFStreamError
), 0);
197 memmove(stream
->error
, err
, sizeof(CFStreamError
));
200 static CFStringRef
__CFStreamCopyDescription(CFTypeRef cf
) {
201 struct _CFStream
*stream
= (struct _CFStream
*)cf
;
202 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
203 CFStringRef contextDescription
;
205 if (cb
->copyDescription
) {
206 if (cb
->version
== 0) {
207 contextDescription
= ((CFStringRef(*)(void *))cb
->copyDescription
)(_CFStreamGetInfoPointer(stream
));
209 contextDescription
= cb
->copyDescription(stream
, _CFStreamGetInfoPointer(stream
));
212 contextDescription
= CFStringCreateWithFormat(CFGetAllocator(stream
), NULL
, CFSTR("info = %p"), _CFStreamGetInfoPointer(stream
));
214 if (CFGetTypeID(cf
) == __kCFReadStreamTypeID
) {
215 desc
= CFStringCreateWithFormat(CFGetAllocator(stream
), NULL
, CFSTR("<CFReadStream %p>{%@}"), stream
, contextDescription
);
217 desc
= CFStringCreateWithFormat(CFGetAllocator(stream
), NULL
, CFSTR("<CFWriteStream %p>{%@}"), stream
, contextDescription
);
219 CFRelease(contextDescription
);
223 static void _CFStreamDetachSource(struct _CFStream
* stream
) {
224 if (stream
&& stream
->client
&& stream
->client
->rlSource
) {
225 if (!__CFBitIsSet(stream
->flags
, SHARED_SOURCE
)) {
226 _CFStreamSetSource(stream
, NULL
, TRUE
);
230 CFArrayRef runLoopAndSourceKey
;
231 CFMutableArrayRef list
;
235 __CFSpinLock(&sSourceLock
);
237 runLoopAndSourceKey
= (CFArrayRef
)CFDictionaryGetValue(sSharedSources
, stream
);
238 list
= (CFMutableArrayRef
)CFDictionaryGetValue(sSharedSources
, runLoopAndSourceKey
);
240 count
= CFArrayGetCount(list
);
241 i
= CFArrayGetFirstIndexOfValue(list
, CFRangeMake(0, count
), stream
);
242 if (i
!= kCFNotFound
) {
243 CFArrayRemoveValueAtIndex(list
, i
);
247 CFAssert(CFArrayGetFirstIndexOfValue(list
, CFRangeMake(0, CFArrayGetCount(list
)), stream
) == kCFNotFound
, __kCFLogAssertion
, "CFStreamClose: stream found twice in its shared source's list");
250 CFRunLoopSourceRef source
= _CFStreamCopySource(stream
);
252 CFRunLoopRemoveSource((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoopAndSourceKey
, 0), source
, (CFStringRef
)CFArrayGetValueAtIndex(runLoopAndSourceKey
, 1));
255 CFDictionaryRemoveValue(sSharedSources
, runLoopAndSourceKey
);
258 CFDictionaryRemoveValue(sSharedSources
, stream
);
260 _CFStreamSetSource(stream
, NULL
, count
== 0);
262 __CFBitClear(stream
->flags
, SHARED_SOURCE
);
264 __CFSpinUnlock(&sSourceLock
);
269 __private_extern__
void _CFStreamClose(struct _CFStream
*stream
) {
270 CFStreamStatus status
= _CFStreamGetStatus(stream
);
271 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
272 if (status
== kCFStreamStatusNotOpen
|| status
== kCFStreamStatusClosed
|| (status
== kCFStreamStatusError
&& __CFBitIsSet(stream
->flags
, HAVE_CLOSED
))) {
273 // Stream is not open from the client's perspective; do not callout and do not update our status to "closed"
276 __CFBitSet(stream
->flags
, HAVE_CLOSED
);
277 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
279 cb
->close(stream
, _CFStreamGetInfoPointer(stream
));
281 if (stream
->client
) {
282 _CFStreamDetachSource(stream
);
284 _CFStreamSetStatusCode(stream
, kCFStreamStatusClosed
);
285 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
288 //static int numStreamInstances = 0;
290 static void __CFStreamDeallocate(CFTypeRef cf
) {
291 struct _CFStream
*stream
= (struct _CFStream
*)cf
;
292 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
293 CFAllocatorRef alloc
= CFGetAllocator(stream
);
294 // numStreamInstances --;
297 _CFStreamClose(stream
);
299 if (stream
->client
) {
300 CFStreamClientContext
*cbContext
;
301 cbContext
= &(stream
->client
->cbContext
);
302 if (cbContext
->info
&& cbContext
->release
) {
303 cbContext
->release(cbContext
->info
);
305 _CFStreamDetachSource(stream
);
306 if (stream
->client
->runLoopsAndModes
) {
307 CFRelease(stream
->client
->runLoopsAndModes
);
310 CFAllocatorDeallocate(alloc
, stream
->client
);
311 stream
->client
= NULL
; // Just in case finalize, below, calls back in to us
314 if (cb
->version
== 0) {
315 ((void(*)(void *))cb
->finalize
)(_CFStreamGetInfoPointer(stream
));
317 cb
->finalize(stream
, _CFStreamGetInfoPointer(stream
));
321 if (cb
->version
< 2) {
322 CFAllocatorDeallocate(alloc
, stream
->error
);
324 CFRelease(stream
->error
);
327 if (!__CFBitIsSet(stream
->flags
, CONSTANT_CALLBACKS
)) {
328 CFAllocatorDeallocate(alloc
, (void *)stream
->callBacks
);
330 if (stream
->_reserved1
)
331 _CFStreamDestroyReserved(alloc
, stream
->_reserved1
);
334 static const CFRuntimeClass __CFReadStreamClass
= {
339 __CFStreamDeallocate
,
342 NULL
, // copyHumanDesc
343 __CFStreamCopyDescription
346 static const CFRuntimeClass __CFWriteStreamClass
= {
351 __CFStreamDeallocate
,
354 NULL
, // copyHumanDesc
355 __CFStreamCopyDescription
358 CONST_STRING_DECL(kCFStreamPropertySocketNativeHandle
, "kCFStreamPropertySocketNativeHandle")
359 CONST_STRING_DECL(kCFStreamPropertySocketRemoteHostName
, "kCFStreamPropertySocketRemoteHostName")
360 CONST_STRING_DECL(kCFStreamPropertySocketRemotePortNumber
, "kCFStreamPropertySocketRemotePortNumber")
361 CONST_STRING_DECL(kCFStreamPropertyDataWritten
, "kCFStreamPropertyDataWritten")
362 CONST_STRING_DECL(kCFStreamPropertyAppendToFile
, "kCFStreamPropertyAppendToFile")
364 __private_extern__
void __CFStreamInitialize(void) {
365 __kCFReadStreamTypeID
= _CFRuntimeRegisterClass(&__CFReadStreamClass
);
366 __kCFWriteStreamTypeID
= _CFRuntimeRegisterClass(&__CFWriteStreamClass
);
370 CF_EXPORT CFTypeID
CFReadStreamGetTypeID(void) {
371 return __kCFReadStreamTypeID
;
374 CF_EXPORT CFTypeID
CFWriteStreamGetTypeID(void) {
375 return __kCFWriteStreamTypeID
;
378 static struct _CFStream
*_CFStreamCreate(CFAllocatorRef allocator
, Boolean isReadStream
) {
379 struct _CFStream
*newStream
= (struct _CFStream
*)_CFRuntimeCreateInstance(allocator
, isReadStream
? __kCFReadStreamTypeID
: __kCFWriteStreamTypeID
, sizeof(struct _CFStream
) - sizeof(CFRuntimeBase
), NULL
);
381 // numStreamInstances ++;
382 newStream
->flags
= 0;
383 _CFStreamSetStatusCode(newStream
, kCFStreamStatusNotOpen
);
384 newStream
->error
= NULL
;
385 newStream
->client
= NULL
;
386 newStream
->info
= NULL
;
387 newStream
->callBacks
= NULL
;
389 newStream
->_reserved1
= _CFStreamCreateReserved(allocator
);
394 __private_extern__
struct _CFStream
*_CFStreamCreateWithConstantCallbacks(CFAllocatorRef alloc
, void *info
, const struct _CFStreamCallBacks
*cb
, Boolean isReading
) {
395 struct _CFStream
*newStream
;
396 if (cb
->version
!= 1) return NULL
;
397 newStream
= _CFStreamCreate(alloc
, isReading
);
399 __CFBitSet(newStream
->flags
, CONSTANT_CALLBACKS
);
400 newStream
->callBacks
= cb
;
402 newStream
->info
= cb
->create(newStream
, info
);
404 newStream
->info
= info
;
410 CF_EXPORT
void _CFStreamSetInfoPointer(struct _CFStream
*stream
, void *info
, const struct _CFStreamCallBacks
*cb
) {
411 if (info
!= stream
->info
) {
412 if (stream
->callBacks
->finalize
) {
413 stream
->callBacks
->finalize(stream
, stream
->info
);
416 stream
->info
= cb
->create(stream
, info
);
421 stream
->callBacks
= cb
;
425 CF_EXPORT CFReadStreamRef
CFReadStreamCreate(CFAllocatorRef alloc
, const CFReadStreamCallBacks
*callbacks
, void *info
) {
426 struct _CFStream
*newStream
= _CFStreamCreate(alloc
, TRUE
);
427 struct _CFStreamCallBacks
*cb
;
428 if (!newStream
) return NULL
;
429 cb
= (struct _CFStreamCallBacks
*)CFAllocatorAllocate(alloc
, sizeof(struct _CFStreamCallBacks
), 0);
431 CFRelease(newStream
);
434 if (callbacks
->version
== 0) {
435 CFReadStreamCallBacksV0
*cbV0
= (CFReadStreamCallBacksV0
*)callbacks
;
436 CFStreamClientContext
*ctxt
= (CFStreamClientContext
*)info
;
437 newStream
->info
= ctxt
->retain
? (void *)ctxt
->retain(ctxt
->info
) : ctxt
->info
;
439 cb
->create
= (void *(*)(struct _CFStream
*, void *))ctxt
->retain
;
440 cb
->finalize
= (void(*)(struct _CFStream
*, void *))ctxt
->release
;
441 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))ctxt
->copyDescription
;
442 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))cbV0
->open
;
443 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))cbV0
->openCompleted
;
444 cb
->read
= (CFIndex (*)(CFReadStreamRef
, UInt8
*, CFIndex
, CFErrorRef
*, Boolean
*, void *))cbV0
->read
;
445 cb
->getBuffer
= (const UInt8
*(*)(CFReadStreamRef
, CFIndex
, CFIndex
*, CFErrorRef
*, Boolean
*, void *))cbV0
->getBuffer
;
446 cb
->canRead
= (Boolean (*)(CFReadStreamRef
, CFErrorRef
*, void*))cbV0
->canRead
;
449 cb
->close
= (void (*)(struct _CFStream
*, void *))cbV0
->close
;
450 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))cbV0
->copyProperty
;
451 cb
->setProperty
= NULL
;
452 cb
->requestEvents
= NULL
;
453 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV0
->schedule
;
454 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV0
->unschedule
;
455 } else if (callbacks
->version
== 1) {
456 CFReadStreamCallBacksV1
*cbV1
= (CFReadStreamCallBacksV1
*)callbacks
;
457 newStream
->info
= cbV1
->create
? cbV1
->create((CFReadStreamRef
)newStream
, info
) : info
;
459 cb
->create
= (void *(*)(struct _CFStream
*, void *))cbV1
->create
;
460 cb
->finalize
= (void(*)(struct _CFStream
*, void *))cbV1
->finalize
;
461 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))cbV1
->copyDescription
;
462 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))cbV1
->open
;
463 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))cbV1
->openCompleted
;
464 cb
->read
= (CFIndex (*)(CFReadStreamRef
, UInt8
*, CFIndex
, CFErrorRef
*, Boolean
*, void *))cbV1
->read
;
465 cb
->getBuffer
= (const UInt8
*(*)(CFReadStreamRef
, CFIndex
, CFIndex
*, CFErrorRef
*, Boolean
*, void *))cbV1
->getBuffer
;
466 cb
->canRead
= (Boolean (*)(CFReadStreamRef
, CFErrorRef
*, void*))cbV1
->canRead
;
469 cb
->close
= (void (*)(struct _CFStream
*, void *))cbV1
->close
;
470 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))cbV1
->copyProperty
;
471 cb
->setProperty
= (Boolean(*)(struct _CFStream
*, CFStringRef
, CFTypeRef
, void *))cbV1
->setProperty
;
472 cb
->requestEvents
= (void(*)(struct _CFStream
*, CFOptionFlags
, void *))cbV1
->requestEvents
;
473 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV1
->schedule
;
474 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV1
->unschedule
;
476 newStream
->info
= callbacks
->create
? callbacks
->create((CFReadStreamRef
)newStream
, info
) : info
;
478 cb
->create
= (void *(*)(struct _CFStream
*, void *))callbacks
->create
;
479 cb
->finalize
= (void(*)(struct _CFStream
*, void *))callbacks
->finalize
;
480 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))callbacks
->copyDescription
;
481 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))callbacks
->open
;
482 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))callbacks
->openCompleted
;
483 cb
->read
= callbacks
->read
;
484 cb
->getBuffer
= callbacks
->getBuffer
;
485 cb
->canRead
= callbacks
->canRead
;
488 cb
->close
= (void (*)(struct _CFStream
*, void *))callbacks
->close
;
489 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))callbacks
->copyProperty
;
490 cb
->setProperty
= (Boolean(*)(struct _CFStream
*, CFStringRef
, CFTypeRef
, void *))callbacks
->setProperty
;
491 cb
->requestEvents
= (void(*)(struct _CFStream
*, CFOptionFlags
, void *))callbacks
->requestEvents
;
492 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))callbacks
->schedule
;
493 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))callbacks
->unschedule
;
496 newStream
->callBacks
= cb
;
497 return (CFReadStreamRef
)newStream
;
500 CF_EXPORT CFWriteStreamRef
CFWriteStreamCreate(CFAllocatorRef alloc
, const CFWriteStreamCallBacks
*callbacks
, void *info
) {
501 struct _CFStream
*newStream
= _CFStreamCreate(alloc
, FALSE
);
502 struct _CFStreamCallBacks
*cb
;
503 if (!newStream
) return NULL
;
504 cb
= (struct _CFStreamCallBacks
*)CFAllocatorAllocate(alloc
, sizeof(struct _CFStreamCallBacks
), 0);
506 CFRelease(newStream
);
509 if (callbacks
->version
== 0) {
510 CFWriteStreamCallBacksV0
*cbV0
= (CFWriteStreamCallBacksV0
*)callbacks
;
511 CFStreamClientContext
*ctxt
= (CFStreamClientContext
*)info
;
512 newStream
->info
= ctxt
->retain
? (void *)ctxt
->retain(ctxt
->info
) : ctxt
->info
;
514 cb
->create
= (void *(*)(struct _CFStream
*, void *))ctxt
->retain
;
515 cb
->finalize
= (void(*)(struct _CFStream
*, void *))ctxt
->release
;
516 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))ctxt
->copyDescription
;
517 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))cbV0
->open
;
518 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))cbV0
->openCompleted
;
520 cb
->getBuffer
= NULL
;
522 cb
->write
= (CFIndex(*)(CFWriteStreamRef stream
, const UInt8
*buffer
, CFIndex bufferLength
, CFErrorRef
*error
, void *info
))cbV0
->write
;
523 cb
->canWrite
= (Boolean(*)(CFWriteStreamRef stream
, CFErrorRef
*error
, void *info
))cbV0
->canWrite
;
524 cb
->close
= (void (*)(struct _CFStream
*, void *))cbV0
->close
;
525 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))cbV0
->copyProperty
;
526 cb
->setProperty
= NULL
;
527 cb
->requestEvents
= NULL
;
528 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV0
->schedule
;
529 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV0
->unschedule
;
530 } else if (callbacks
->version
== 1) {
531 CFWriteStreamCallBacksV1
*cbV1
= (CFWriteStreamCallBacksV1
*)callbacks
;
533 newStream
->info
= cbV1
->create
? cbV1
->create((CFWriteStreamRef
)newStream
, info
) : info
;
534 cb
->create
= (void *(*)(struct _CFStream
*, void *))cbV1
->create
;
535 cb
->finalize
= (void(*)(struct _CFStream
*, void *))cbV1
->finalize
;
536 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))cbV1
->copyDescription
;
537 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))cbV1
->open
;
538 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))cbV1
->openCompleted
;
540 cb
->getBuffer
= NULL
;
542 cb
->write
= (CFIndex(*)(CFWriteStreamRef stream
, const UInt8
*buffer
, CFIndex bufferLength
, CFErrorRef
*error
, void *info
))cbV1
->write
;
543 cb
->canWrite
= (Boolean(*)(CFWriteStreamRef stream
, CFErrorRef
*error
, void *info
))cbV1
->canWrite
;
544 cb
->close
= (void (*)(struct _CFStream
*, void *))cbV1
->close
;
545 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))cbV1
->copyProperty
;
546 cb
->setProperty
= (Boolean (*)(struct _CFStream
*, CFStringRef
, CFTypeRef
, void *))cbV1
->setProperty
;
547 cb
->requestEvents
= (void(*)(struct _CFStream
*, CFOptionFlags
, void *))cbV1
->requestEvents
;
548 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV1
->schedule
;
549 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV1
->unschedule
;
551 cb
->version
= callbacks
->version
;
552 newStream
->info
= callbacks
->create
? callbacks
->create((CFWriteStreamRef
)newStream
, info
) : info
;
553 cb
->create
= (void *(*)(struct _CFStream
*, void *))callbacks
->create
;
554 cb
->finalize
= (void(*)(struct _CFStream
*, void *))callbacks
->finalize
;
555 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))callbacks
->copyDescription
;
556 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))callbacks
->open
;
557 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))callbacks
->openCompleted
;
559 cb
->getBuffer
= NULL
;
561 cb
->write
= callbacks
->write
;
562 cb
->canWrite
= callbacks
->canWrite
;
563 cb
->close
= (void (*)(struct _CFStream
*, void *))callbacks
->close
;
564 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))callbacks
->copyProperty
;
565 cb
->setProperty
= (Boolean (*)(struct _CFStream
*, CFStringRef
, CFTypeRef
, void *))callbacks
->setProperty
;
566 cb
->requestEvents
= (void(*)(struct _CFStream
*, CFOptionFlags
, void *))callbacks
->requestEvents
;
567 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))callbacks
->schedule
;
568 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))callbacks
->unschedule
;
570 newStream
->callBacks
= cb
;
571 return (CFWriteStreamRef
)newStream
;
574 static void _signalEventSync(struct _CFStream
* stream
, CFOptionFlags whatToSignal
)
576 CFOptionFlags eventMask
;
578 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
581 void (*release
) (void*) = NULL
;
583 if (stream
->client
->cbContext
.retain
== NULL
)
584 info
= stream
->client
->cbContext
.info
;
586 info
= stream
->client
->cbContext
.retain(stream
->client
->cbContext
.info
);
587 release
= stream
->client
->cbContext
.release
;
590 for (eventMask
= 1; eventMask
<= whatToSignal
; eventMask
= eventMask
<< 1) {
591 if ((eventMask
& whatToSignal
) && (stream
->client
->when
& eventMask
)) {
592 stream
->client
->cb(stream
, eventMask
, info
);
594 /* What happens if the callback sets the client to NULL? We're in a loop here... Hmm. */
595 /* After writing that comment, I see: <rdar://problem/6793636> CFReadStreamSetClient(..., NULL) unsafely releases info pointer immediately */
596 /* Of note, when the stream callbacks are set to to NULL, we're re-initalized so as not to receive more events, so we
597 * should break pout of this loop */
604 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
607 static void _cfstream_solo_signalEventSync(void* info
)
609 CFTypeID typeID
= CFGetTypeID((CFTypeRef
) info
);
611 if (typeID
!= CFReadStreamGetTypeID() && typeID
!= CFWriteStreamGetTypeID()) {
612 CFLog(__kCFLogAssertion
, CFSTR("Expected an read or write stream for %p"), info
);
617 struct _CFStream
* stream
= (struct _CFStream
*) info
;
618 CFOptionFlags whatToSignal
= stream
->client
->whatToSignal
;
619 stream
->client
->whatToSignal
= 0;
621 /* Since the array version holds a retain, we do it here as well, as opposed to taking a second retain in the client callback */
623 _signalEventSync(stream
, whatToSignal
);
628 static void _cfstream_shared_signalEventSync(void* info
)
630 CFTypeID typeID
= CFGetTypeID((CFTypeRef
) info
);
632 if (typeID
!= CFArrayGetTypeID()) {
633 CFLog(__kCFLogAssertion
, CFSTR("Expected an array for %p"), info
);
638 CFMutableArrayRef list
= (CFMutableArrayRef
) info
;
640 CFOptionFlags whatToSignal
= 0;
641 struct _CFStream
* stream
= NULL
;
643 __CFSpinLock(&sSourceLock
);
645 /* Looks like, we grab the first stream that wants an event... */
646 /* Note that I grab an extra retain when I pull out the stream here... */
647 c
= CFArrayGetCount(list
);
648 for (i
= 0; i
< c
; i
++) {
649 struct _CFStream
* s
= (struct _CFStream
*)CFArrayGetValueAtIndex(list
, i
);
651 if (s
->client
->whatToSignal
) {
654 whatToSignal
= stream
->client
->whatToSignal
;
655 s
->client
->whatToSignal
= 0;
660 /* And then we also signal any other streams in this array so that we get them next go? */
662 struct _CFStream
* s
= (struct _CFStream
*)CFArrayGetValueAtIndex(list
, i
);
663 if (s
->client
->whatToSignal
) {
664 CFRunLoopSourceRef source
= _CFStreamCopySource(s
);
666 CFRunLoopSourceSignal(source
);
673 __CFSpinUnlock(&sSourceLock
);
675 /* We're sitting here now, possibly with a stream that needs to be processed by the common routine */
677 _signalEventSync(stream
, whatToSignal
);
679 /* Lose our extra retain */
685 /* This routine is to be considered unsafe... */
686 static CFArrayRef
_CFStreamGetRunLoopsAndModes(struct _CFStream
*stream
)
688 CFArrayRef result
= NULL
;
689 if (stream
&& stream
->client
) {
690 _CFStreamLock(stream
);
691 struct CFStreamAux
* aux
= _CFStreamGetAuxRecord(stream
);
692 if (aux
->previousRunloopsAndModes
) {
693 CFRelease(aux
->previousRunloopsAndModes
);
694 aux
->previousRunloopsAndModes
= NULL
;
696 if (stream
->client
->runLoopsAndModes
) {
697 aux
->previousRunloopsAndModes
= CFArrayCreateCopy(CFGetAllocator(stream
), stream
->client
->runLoopsAndModes
);
699 result
= aux
->previousRunloopsAndModes
;
700 checkRLMArray(result
);
701 _CFStreamUnlock(stream
);
706 static CFArrayRef
_CFStreamCopyRunLoopsAndModes(struct _CFStream
*stream
)
708 CFArrayRef result
= NULL
;
709 if (stream
&& stream
->client
) {
710 _CFStreamLock(stream
);
711 if (stream
->client
->runLoopsAndModes
) {
712 result
= CFArrayCreateCopy(CFGetAllocator(stream
), stream
->client
->runLoopsAndModes
);
714 checkRLMArray(result
);
715 _CFStreamUnlock(stream
);
720 static void _wakeUpRunLoop(struct _CFStream
*stream
) {
721 CFArrayRef rlArray
= _CFStreamCopyRunLoopsAndModes(stream
);
723 CFIndex cnt
= CFArrayGetCount(rlArray
);
724 CFRunLoopRef rl
= NULL
;
727 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, 0);
728 } else if (cnt
> 2) {
730 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, 0);
731 for (idx
= 2; NULL
!= rl
&& idx
< cnt
; idx
+=2) {
732 CFRunLoopRef value
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, idx
);
733 if (value
!= rl
) rl
= NULL
;
735 if (NULL
== rl
) { /* more than one different rl, so we must pick one */
736 for (idx
= 0; idx
< cnt
; idx
+=2) {
737 CFRunLoopRef value
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, idx
);
738 CFStringRef currentMode
= CFRunLoopCopyCurrentMode(value
);
739 if (NULL
!= currentMode
&& CFEqual(currentMode
, CFArrayGetValueAtIndex(rlArray
, idx
+1)) && CFRunLoopIsWaiting(value
)) {
740 CFRelease(currentMode
);
744 if (NULL
!= currentMode
) CFRelease(currentMode
);
746 if (NULL
== rl
) { /* didn't choose one above, so choose first */
747 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, 0);
751 if (NULL
!= rl
&& CFRunLoopIsWaiting(rl
))
757 __private_extern__
void _CFStreamSignalEvent(struct _CFStream
*stream
, CFStreamEventType event
, CFErrorRef error
, Boolean synchronousAllowed
) {
758 // Update our internal status; we must use the primitive __CFStreamGetStatus(), because CFStreamGetStatus() calls us, and we can end up in an infinite loop.
759 CFStreamStatus status
= __CFStreamGetStatus(stream
);
761 // Sanity check the event
762 if (status
== kCFStreamStatusNotOpen
) {
763 // No events allowed; this is almost certainly a bug in the stream's implementation
764 CFLog(__kCFLogAssertion
, CFSTR("Stream %p is sending an event before being opened"), stream
);
766 } else if (status
== kCFStreamStatusClosed
|| status
== kCFStreamStatusError
) {
767 // no further events are allowed
769 } else if (status
== kCFStreamStatusAtEnd
) {
770 // Only error events are allowed
771 event
&= kCFStreamEventErrorOccurred
;
772 } else if (status
!= kCFStreamStatusOpening
) {
773 // cannot send open completed; that happened already
774 event
&= ~kCFStreamEventOpenCompleted
;
777 // Change status if appropriate
778 if (event
& kCFStreamEventOpenCompleted
&& status
== kCFStreamStatusOpening
) {
779 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
781 if (event
& kCFStreamEventEndEncountered
&& status
< kCFStreamStatusAtEnd
) {
782 _CFStreamSetStatusCode(stream
, kCFStreamStatusAtEnd
);
784 if (event
& kCFStreamEventErrorOccurred
) {
785 if (_CFStreamGetCallBackPtr(stream
)->version
< 2) {
786 _CFStreamSetStreamError(stream
, (CFStreamError
*)error
);
788 CFAssert(error
, __kCFLogAssertion
, "CFStream: kCFStreamEventErrorOccurred signalled, but error is NULL!");
790 if (stream
->error
) CFRelease(stream
->error
);
791 stream
->error
= error
;
793 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
796 // Now signal any pertinent event
797 if (stream
->client
&& (stream
->client
->when
& event
) != 0) {
798 CFRunLoopSourceRef source
= _CFStreamCopySource(stream
);
801 Boolean signalNow
= FALSE
;
803 stream
->client
->whatToSignal
|= event
;
805 if (synchronousAllowed
&& !__CFBitIsSet(stream
->flags
, CALLING_CLIENT
)) {
807 CFRunLoopRef rl
= CFRunLoopGetCurrent();
808 CFStringRef mode
= CFRunLoopCopyCurrentMode(rl
);
811 if (CFRunLoopContainsSource(rl
, source
, mode
))
819 // Can call out safely right now
820 _cfstream_solo_signalEventSync(stream
);
822 // Schedule for later delivery
824 CFRunLoopSourceSignal(source
);
826 _wakeUpRunLoop(stream
);
834 __private_extern__ CFStreamStatus
_CFStreamGetStatus(struct _CFStream
*stream
) {
835 CFStreamStatus status
= __CFStreamGetStatus(stream
);
836 // 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.
837 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
838 if (status
== kCFStreamStatusOpening
) {
839 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
840 if (cb
->openCompleted
) {
842 if (cb
->version
< 2) {
843 CFStreamError err
= {0, 0};
844 isComplete
= ((_CFStreamCBOpenCompletedV1
)(cb
->openCompleted
))(stream
, &err
, _CFStreamGetInfoPointer(stream
));
845 if (err
.error
!= 0) _CFStreamSetStreamError(stream
, &err
);
847 isComplete
= cb
->openCompleted(stream
, &(stream
->error
), _CFStreamGetInfoPointer(stream
));
850 if (!stream
->error
) {
851 status
= kCFStreamStatusOpen
;
853 status
= kCFStreamStatusError
;
855 _CFStreamSetStatusCode(stream
, status
);
856 if (status
== kCFStreamStatusOpen
) {
857 _CFStreamScheduleEvent(stream
, kCFStreamEventOpenCompleted
);
859 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
864 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
868 CF_EXPORT CFStreamStatus
CFReadStreamGetStatus(CFReadStreamRef stream
) {
869 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID
, CFStreamStatus
, (NSInputStream
*)stream
, streamStatus
);
870 return _CFStreamGetStatus((struct _CFStream
*)stream
);
873 CF_EXPORT CFStreamStatus
CFWriteStreamGetStatus(CFWriteStreamRef stream
) {
874 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID
, CFStreamStatus
, (NSOutputStream
*)stream
, streamStatus
);
875 return _CFStreamGetStatus((struct _CFStream
*)stream
);
878 static CFStreamError
_CFStreamGetStreamError(struct _CFStream
*stream
) {
879 CFStreamError result
;
880 if (!stream
->error
) {
883 } else if (_CFStreamGetCallBackPtr(stream
)->version
< 2) {
884 CFStreamError
*streamError
= (CFStreamError
*)(stream
->error
);
885 result
.error
= streamError
->error
;
886 result
.domain
= streamError
->domain
;
888 result
= _CFStreamErrorFromError(stream
->error
);
893 CF_EXPORT CFStreamError
CFReadStreamGetError(CFReadStreamRef stream
) {
894 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID
, CFStreamError
, (NSInputStream
*)stream
, _cfStreamError
);
895 return _CFStreamGetStreamError((struct _CFStream
*)stream
);
898 CF_EXPORT CFStreamError
CFWriteStreamGetError(CFWriteStreamRef stream
) {
899 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID
, CFStreamError
, (NSOutputStream
*)stream
, _cfStreamError
);
900 return _CFStreamGetStreamError((struct _CFStream
*)stream
);
903 static CFErrorRef
_CFStreamCopyError(struct _CFStream
*stream
) {
904 if (!stream
->error
) {
906 } else if (_CFStreamGetCallBackPtr(stream
)->version
< 2) {
907 return _CFErrorFromStreamError(CFGetAllocator(stream
), (CFStreamError
*)(stream
->error
));
909 CFRetain(stream
->error
);
910 return stream
->error
;
914 CF_EXPORT CFErrorRef
CFReadStreamCopyError(CFReadStreamRef stream
) {
915 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID
, CFErrorRef
, (NSInputStream
*)stream
, streamError
);
916 return _CFStreamCopyError((struct _CFStream
*)stream
);
919 CF_EXPORT CFErrorRef
CFWriteStreamCopyError(CFWriteStreamRef stream
) {
920 return _CFStreamCopyError((struct _CFStream
*)stream
);
921 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID
, CFErrorRef
, (NSOutputStream
*)stream
, streamError
);
924 __private_extern__ Boolean
_CFStreamOpen(struct _CFStream
*stream
) {
925 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
926 Boolean success
, openComplete
;
927 if (_CFStreamGetStatus(stream
) != kCFStreamStatusNotOpen
) {
930 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
931 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpening
);
933 if (cb
->version
< 2) {
934 CFStreamError err
= {0, 0};
935 success
= ((_CFStreamCBOpenV1
)(cb
->open
))(stream
, &err
, &openComplete
, _CFStreamGetInfoPointer(stream
));
936 if (err
.error
!= 0) _CFStreamSetStreamError(stream
, &err
);
938 success
= cb
->open(stream
, &(stream
->error
), &openComplete
, _CFStreamGetInfoPointer(stream
));
946 // 2957690 - Guard against the possibility that the stream has already signalled itself in to a later state (like AtEnd)
947 if (__CFStreamGetStatus(stream
) == kCFStreamStatusOpening
) {
948 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
950 _CFStreamScheduleEvent(stream
, kCFStreamEventOpenCompleted
);
952 #if DEPLOYMENT_TARGET_WINDOWS
953 _CFStreamClose(stream
);
955 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
956 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
959 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
963 CF_EXPORT Boolean
CFReadStreamOpen(CFReadStreamRef stream
) {
964 if(CF_IS_OBJC(__kCFReadStreamTypeID
, stream
)) {
965 (void)CF_OBJC_CALLV((NSInputStream
*)stream
, open
);
968 return _CFStreamOpen((struct _CFStream
*)stream
);
971 CF_EXPORT Boolean
CFWriteStreamOpen(CFWriteStreamRef stream
) {
972 if(CF_IS_OBJC(__kCFWriteStreamTypeID
, stream
)) {
973 (void)CF_OBJC_CALLV((NSOutputStream
*)stream
, open
);
976 return _CFStreamOpen((struct _CFStream
*)stream
);
979 CF_EXPORT
void CFReadStreamClose(CFReadStreamRef stream
) {
980 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID
, void, (NSInputStream
*)stream
, close
);
981 _CFStreamClose((struct _CFStream
*)stream
);
984 CF_EXPORT
void CFWriteStreamClose(CFWriteStreamRef stream
) {
985 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID
, void, (NSOutputStream
*)stream
, close
);
986 _CFStreamClose((struct _CFStream
*)stream
);
989 CF_EXPORT Boolean
CFReadStreamHasBytesAvailable(CFReadStreamRef readStream
) {
990 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID
, Boolean
, (NSInputStream
*)readStream
, hasBytesAvailable
);
991 struct _CFStream
*stream
= (struct _CFStream
*)readStream
;
992 CFStreamStatus status
= _CFStreamGetStatus(stream
);
993 const struct _CFStreamCallBacks
*cb
;
994 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusReading
) {
997 cb
= _CFStreamGetCallBackPtr(stream
);
998 if (cb
->canRead
== NULL
) {
999 return TRUE
; // No way to know without trying....
1002 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1003 if (cb
->version
< 2) {
1004 result
= ((_CFStreamCBCanReadV1
)(cb
->canRead
))((CFReadStreamRef
)stream
, _CFStreamGetInfoPointer(stream
));
1006 result
= cb
->canRead((CFReadStreamRef
)stream
, &(stream
->error
), _CFStreamGetInfoPointer(stream
));
1007 if (stream
->error
) {
1008 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
1009 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
1012 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1017 static void waitForOpen(struct _CFStream
*stream
);
1018 CFIndex
CFReadStreamRead(CFReadStreamRef readStream
, UInt8
*buffer
, CFIndex bufferLength
) {
1019 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID
, CFIndex
, (NSInputStream
*)readStream
, read
:(uint8_t *)buffer maxLength
:(NSUInteger
)bufferLength
);
1020 struct _CFStream
*stream
= (struct _CFStream
*)readStream
;
1021 CFStreamStatus status
= _CFStreamGetStatus(stream
);
1022 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1023 if (status
== kCFStreamStatusOpening
) {
1024 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1025 waitForOpen(stream
);
1026 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1027 status
= _CFStreamGetStatus(stream
);
1030 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusReading
&& status
!= kCFStreamStatusAtEnd
) {
1032 } else if (status
== kCFStreamStatusAtEnd
) {
1037 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1038 if (stream
->client
) {
1039 stream
->client
->whatToSignal
&= ~kCFStreamEventHasBytesAvailable
;
1041 _CFStreamSetStatusCode(stream
, kCFStreamStatusReading
);
1042 if (cb
->version
< 2) {
1043 CFStreamError err
= {0, 0};
1044 bytesRead
= ((_CFStreamCBReadV1
)(cb
->read
))((CFReadStreamRef
)stream
, buffer
, bufferLength
, &err
, &atEOF
, _CFStreamGetInfoPointer(stream
));
1045 if (err
.error
!= 0) _CFStreamSetStreamError(stream
, &err
);
1047 bytesRead
= cb
->read((CFReadStreamRef
)stream
, buffer
, bufferLength
, &(stream
->error
), &atEOF
, _CFStreamGetInfoPointer(stream
));
1049 if (stream
->error
) {
1051 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
1052 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
1054 _CFStreamSetStatusCode(stream
, kCFStreamStatusAtEnd
);
1055 _CFStreamScheduleEvent(stream
, kCFStreamEventEndEncountered
);
1057 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
1059 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1064 CF_EXPORT
const UInt8
*CFReadStreamGetBuffer(CFReadStreamRef readStream
, CFIndex maxBytesToRead
, CFIndex
*numBytesRead
) {
1065 if (CF_IS_OBJC(__kCFReadStreamTypeID
, readStream
)) {
1066 uint8_t *bufPtr
= NULL
;
1067 Boolean gotBytes
= (Boolean
) CF_OBJC_CALLV((NSInputStream
*)readStream
, getBuffer
:&bufPtr length
:(NSUInteger
*)numBytesRead
);
1069 return (const UInt8
*)bufPtr
;
1074 struct _CFStream
*stream
= (struct _CFStream
*)readStream
;
1075 CFStreamStatus status
= _CFStreamGetStatus(stream
);
1076 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1077 const UInt8
*buffer
;
1078 if (status
== kCFStreamStatusOpening
) {
1079 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1080 waitForOpen(stream
);
1081 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1082 status
= _CFStreamGetStatus(stream
);
1084 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusReading
&& status
!= kCFStreamStatusAtEnd
) {
1087 } else if (status
== kCFStreamStatusAtEnd
|| cb
->getBuffer
== NULL
) {
1092 Boolean hadBytes
= stream
->client
&& (stream
->client
->whatToSignal
& kCFStreamEventHasBytesAvailable
);
1093 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1095 stream
->client
->whatToSignal
&= ~kCFStreamEventHasBytesAvailable
;
1097 _CFStreamSetStatusCode(stream
, kCFStreamStatusReading
);
1098 if (cb
->version
< 2) {
1099 CFStreamError err
= {0, 0};
1100 buffer
= ((_CFStreamCBGetBufferV1
)(cb
->getBuffer
))((CFReadStreamRef
)stream
, maxBytesToRead
, numBytesRead
, &err
, &atEOF
, _CFStreamGetInfoPointer(stream
));
1101 if (err
.error
!= 0) _CFStreamSetStreamError(stream
, &err
);
1103 buffer
= cb
->getBuffer((CFReadStreamRef
)stream
, maxBytesToRead
, numBytesRead
, &(stream
->error
), &atEOF
, _CFStreamGetInfoPointer(stream
));
1105 if (stream
->error
) {
1107 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
1109 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
1111 _CFStreamSetStatusCode(stream
, kCFStreamStatusAtEnd
);
1112 _CFStreamScheduleEvent(stream
, kCFStreamEventEndEncountered
);
1114 if (!buffer
&& hadBytes
) {
1115 stream
->client
->whatToSignal
|= kCFStreamEventHasBytesAvailable
;
1117 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
1119 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1124 CF_EXPORT Boolean
CFWriteStreamCanAcceptBytes(CFWriteStreamRef writeStream
) {
1125 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID
, Boolean
, (NSOutputStream
*)writeStream
, hasSpaceAvailable
);
1126 struct _CFStream
*stream
= (struct _CFStream
*)writeStream
;
1127 CFStreamStatus status
= _CFStreamGetStatus(stream
);
1128 const struct _CFStreamCallBacks
*cb
;
1129 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusWriting
) {
1132 cb
= _CFStreamGetCallBackPtr(stream
);
1133 if (cb
->canWrite
== NULL
) {
1134 return TRUE
; // No way to know without trying....
1137 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1138 if (cb
->version
< 2) {
1139 result
= ((_CFStreamCBCanWriteV1
)(cb
->canWrite
))((CFWriteStreamRef
)stream
, _CFStreamGetInfoPointer(stream
));
1141 result
= cb
->canWrite((CFWriteStreamRef
)stream
, &(stream
->error
), _CFStreamGetInfoPointer(stream
));
1142 if (stream
->error
) {
1143 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
1144 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
1147 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1152 CF_EXPORT CFIndex
CFWriteStreamWrite(CFWriteStreamRef writeStream
, const UInt8
*buffer
, CFIndex bufferLength
) {
1153 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID
, CFIndex
, (NSOutputStream
*)writeStream
, write
:(const uint8_t *)buffer maxLength
:(NSUInteger
)bufferLength
);
1154 struct _CFStream
*stream
= (struct _CFStream
*)writeStream
;
1155 CFStreamStatus status
= _CFStreamGetStatus(stream
);
1156 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1157 if (status
== kCFStreamStatusOpening
) {
1158 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1159 waitForOpen(stream
);
1160 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1161 status
= _CFStreamGetStatus(stream
);
1163 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusWriting
) {
1167 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1168 _CFStreamSetStatusCode(stream
, kCFStreamStatusWriting
);
1169 if (stream
->client
) {
1170 stream
->client
->whatToSignal
&= ~kCFStreamEventCanAcceptBytes
;
1172 if (cb
->version
< 2) {
1173 CFStreamError err
= {0, 0};
1174 result
= ((_CFStreamCBWriteV1
)(cb
->write
))((CFWriteStreamRef
)stream
, buffer
, bufferLength
, &err
, _CFStreamGetInfoPointer(stream
));
1175 if (err
.error
) _CFStreamSetStreamError(stream
, &err
);
1177 result
= cb
->write((CFWriteStreamRef
)stream
, buffer
, bufferLength
, &(stream
->error
), _CFStreamGetInfoPointer(stream
));
1179 if (stream
->error
) {
1180 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
1181 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
1182 } else if (result
== 0) {
1183 _CFStreamSetStatusCode(stream
, kCFStreamStatusAtEnd
);
1184 _CFStreamScheduleEvent(stream
, kCFStreamEventEndEncountered
);
1186 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
1188 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1193 __private_extern__ CFTypeRef
_CFStreamCopyProperty(struct _CFStream
*stream
, CFStringRef propertyName
) {
1194 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1195 if (cb
->copyProperty
== NULL
) {
1199 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1200 result
= cb
->copyProperty(stream
, propertyName
, _CFStreamGetInfoPointer(stream
));
1201 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1206 CF_EXPORT CFTypeRef
CFReadStreamCopyProperty(CFReadStreamRef stream
, CFStringRef propertyName
) {
1207 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID
, CFTypeRef
, (NSInputStream
*)stream
, propertyForKey
:(NSString
*)propertyName
);
1208 return _CFStreamCopyProperty((struct _CFStream
*)stream
, propertyName
);
1211 CF_EXPORT CFTypeRef
CFWriteStreamCopyProperty(CFWriteStreamRef stream
, CFStringRef propertyName
) {
1212 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID
, CFTypeRef
, (NSOutputStream
*)stream
, propertyForKey
:(NSString
*)propertyName
);
1213 return _CFStreamCopyProperty((struct _CFStream
*)stream
, propertyName
);
1216 __private_extern__ Boolean
_CFStreamSetProperty(struct _CFStream
*stream
, CFStringRef prop
, CFTypeRef val
) {
1217 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1218 if (cb
->setProperty
== NULL
) {
1222 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1223 result
= cb
->setProperty(stream
, prop
, val
, _CFStreamGetInfoPointer(stream
));
1224 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1230 Boolean
CFReadStreamSetProperty(CFReadStreamRef stream
, CFStringRef propertyName
, CFTypeRef propertyValue
) {
1231 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID
, Boolean
, (NSInputStream
*)stream
, setProperty
:(id
)propertyValue forKey
:(NSString
*)propertyName
);
1232 return _CFStreamSetProperty((struct _CFStream
*)stream
, propertyName
, propertyValue
);
1236 Boolean
CFWriteStreamSetProperty(CFWriteStreamRef stream
, CFStringRef propertyName
, CFTypeRef propertyValue
) {
1237 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID
, Boolean
, (NSOutputStream
*)stream
, setProperty
:(id
)propertyValue forKey
:(NSString
*)propertyName
);
1238 return _CFStreamSetProperty((struct _CFStream
*)stream
, propertyName
, propertyValue
);
1241 static void _initializeClient(struct _CFStream
*stream
) {
1242 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1243 if (!cb
->schedule
) return; // Do we wish to allow this?
1244 stream
->client
= (struct _CFStreamClient
*)CFAllocatorAllocate(CFGetAllocator(stream
), sizeof(struct _CFStreamClient
), 0);
1245 memset(stream
->client
, 0, sizeof(struct _CFStreamClient
));
1248 /* If we add a setClient callback to the concrete stream callbacks, we must set/clear CALLING_CLIENT around it */
1249 __private_extern__ Boolean
_CFStreamSetClient(struct _CFStream
*stream
, CFOptionFlags streamEvents
, void (*clientCB
)(struct _CFStream
*, CFStreamEventType
, void *), CFStreamClientContext
*clientCallBackContext
) {
1251 Boolean removingClient
= (streamEvents
== kCFStreamEventNone
|| clientCB
== NULL
|| clientCallBackContext
== NULL
);
1253 if (removingClient
) {
1255 streamEvents
= kCFStreamEventNone
;
1256 clientCallBackContext
= NULL
;
1258 if (!stream
->client
) {
1259 if (removingClient
) {
1260 // We have no client now, and we've been asked to add none???
1263 _initializeClient(stream
);
1264 if (!stream
->client
) {
1265 // Asynch not supported
1269 if (stream
->client
->cb
&& stream
->client
->cbContext
.release
) {
1270 stream
->client
->cbContext
.release(stream
->client
->cbContext
.info
);
1272 stream
->client
->cb
= clientCB
;
1273 if (clientCallBackContext
) {
1274 stream
->client
->cbContext
.version
= clientCallBackContext
->version
;
1275 stream
->client
->cbContext
.retain
= clientCallBackContext
->retain
;
1276 stream
->client
->cbContext
.release
= clientCallBackContext
->release
;
1277 stream
->client
->cbContext
.copyDescription
= clientCallBackContext
->copyDescription
;
1278 stream
->client
->cbContext
.info
= (clientCallBackContext
->retain
&& clientCallBackContext
->info
) ? clientCallBackContext
->retain(clientCallBackContext
->info
) : clientCallBackContext
->info
;
1280 stream
->client
->cbContext
.retain
= NULL
;
1281 stream
->client
->cbContext
.release
= NULL
;
1282 stream
->client
->cbContext
.copyDescription
= NULL
;
1283 stream
->client
->cbContext
.info
= NULL
;
1285 if (stream
->client
->when
!= streamEvents
) {
1286 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1287 stream
->client
->when
= streamEvents
;
1288 if (cb
->requestEvents
) {
1289 cb
->requestEvents(stream
, streamEvents
, _CFStreamGetInfoPointer(stream
));
1295 CF_EXPORT Boolean
CFReadStreamSetClient(CFReadStreamRef readStream
, CFOptionFlags streamEvents
, CFReadStreamClientCallBack clientCB
, CFStreamClientContext
*clientContext
) {
1296 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID
, Boolean
, (NSInputStream
*)readStream
, _setCFClientFlags
:streamEvents callback
:clientCB context
:clientContext
);
1297 streamEvents
&= ~kCFStreamEventCanAcceptBytes
;
1298 return _CFStreamSetClient((struct _CFStream
*)readStream
, streamEvents
, (void (*)(struct _CFStream
*, CFStreamEventType
, void *))clientCB
, clientContext
);
1301 CF_EXPORT Boolean
CFWriteStreamSetClient(CFWriteStreamRef writeStream
, CFOptionFlags streamEvents
, CFWriteStreamClientCallBack clientCB
, CFStreamClientContext
*clientContext
) {
1302 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID
, Boolean
, (NSOutputStream
*)writeStream
, _setCFClientFlags
:streamEvents callback
:clientCB context
:clientContext
);
1303 streamEvents
&= ~kCFStreamEventHasBytesAvailable
;
1304 return _CFStreamSetClient((struct _CFStream
*)writeStream
, streamEvents
, (void (*)(struct _CFStream
*, CFStreamEventType
, void *))clientCB
, clientContext
);
1307 CF_INLINE
void *_CFStreamGetClient(struct _CFStream
*stream
) {
1308 if (stream
->client
) return stream
->client
->cbContext
.info
;
1312 CF_EXPORT
void *_CFReadStreamGetClient(CFReadStreamRef readStream
) {
1313 return _CFStreamGetClient((struct _CFStream
*)readStream
);
1316 CF_EXPORT
void *_CFWriteStreamGetClient(CFWriteStreamRef writeStream
) {
1317 return _CFStreamGetClient((struct _CFStream
*)writeStream
);
1321 __private_extern__
void _CFStreamScheduleWithRunLoop(struct _CFStream
*stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1322 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1324 if (! stream
->client
) {
1325 _initializeClient(stream
);
1326 if (!stream
->client
) return; // we don't support asynch.
1329 if (! stream
->client
->rlSource
) {
1330 /* No source, so we join the shared source group */
1331 CFTypeRef a
[] = { runLoop
, runLoopMode
};
1333 CFArrayRef runLoopAndSourceKey
= CFArrayCreate(kCFAllocatorSystemDefault
, a
, sizeof(a
) / sizeof(a
[0]), &kCFTypeArrayCallBacks
);
1335 __CFSpinLock(&sSourceLock
);
1337 if (!sSharedSources
)
1338 sSharedSources
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1340 CFMutableArrayRef listOfStreamsSharingASource
= (CFMutableArrayRef
)CFDictionaryGetValue(sSharedSources
, runLoopAndSourceKey
);
1341 if (listOfStreamsSharingASource
) {
1342 struct _CFStream
* aStream
= (struct _CFStream
*) CFArrayGetValueAtIndex(listOfStreamsSharingASource
, 0);
1343 CFRunLoopSourceRef source
= _CFStreamCopySource(aStream
);
1345 _CFStreamSetSource(stream
, source
, FALSE
);
1348 CFRetain(listOfStreamsSharingASource
);
1351 CFRunLoopSourceContext ctxt
= {
1356 (CFStringRef(*)(const void *))CFCopyDescription
,
1361 (void(*)(void *))_cfstream_shared_signalEventSync
1364 listOfStreamsSharingASource
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
1365 CFDictionaryAddValue(sSharedSources
, runLoopAndSourceKey
, listOfStreamsSharingASource
);
1367 ctxt
.info
= listOfStreamsSharingASource
;
1369 CFRunLoopSourceRef source
= CFRunLoopSourceCreate(kCFAllocatorSystemDefault
, 0, &ctxt
);
1370 _CFStreamSetSource(stream
, source
, FALSE
);
1371 CFRunLoopAddSource(runLoop
, source
, runLoopMode
);
1375 CFArrayAppendValue(listOfStreamsSharingASource
, stream
);
1376 CFDictionaryAddValue(sSharedSources
, stream
, runLoopAndSourceKey
);
1378 CFRelease(runLoopAndSourceKey
);
1379 CFRelease(listOfStreamsSharingASource
);
1381 __CFBitSet(stream
->flags
, SHARED_SOURCE
);
1383 __CFSpinUnlock(&sSourceLock
);
1385 else if (__CFBitIsSet(stream
->flags
, SHARED_SOURCE
)) {
1386 /* We were sharing, but now we'll get our own source */
1388 CFArrayRef runLoopAndSourceKey
;
1389 CFMutableArrayRef listOfStreamsSharingASource
;
1392 CFAllocatorRef alloc
= CFGetAllocator(stream
);
1393 CFRunLoopSourceContext ctxt
= {
1396 NULL
, // Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop
1397 NULL
, // Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop
1398 (CFStringRef(*)(const void *))CFCopyDescription
,
1403 (void(*)(void *))_cfstream_solo_signalEventSync
1406 __CFSpinLock(&sSourceLock
);
1408 runLoopAndSourceKey
= (CFArrayRef
)CFRetain((CFTypeRef
)CFDictionaryGetValue(sSharedSources
, stream
));
1409 listOfStreamsSharingASource
= (CFMutableArrayRef
)CFDictionaryGetValue(sSharedSources
, runLoopAndSourceKey
);
1411 count
= CFArrayGetCount(listOfStreamsSharingASource
);
1412 i
= CFArrayGetFirstIndexOfValue(listOfStreamsSharingASource
, CFRangeMake(0, count
), stream
);
1413 if (i
!= kCFNotFound
) {
1414 CFArrayRemoveValueAtIndex(listOfStreamsSharingASource
, i
);
1419 CFRunLoopSourceRef source
= _CFStreamCopySource(stream
);
1421 CFRunLoopRemoveSource((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoopAndSourceKey
, 0), source
, (CFStringRef
)CFArrayGetValueAtIndex(runLoopAndSourceKey
, 1));
1424 CFDictionaryRemoveValue(sSharedSources
, runLoopAndSourceKey
);
1427 CFDictionaryRemoveValue(sSharedSources
, stream
);
1429 _CFStreamSetSource(stream
, NULL
, count
== 0);
1431 __CFBitClear(stream
->flags
, SHARED_SOURCE
);
1433 __CFSpinUnlock(&sSourceLock
);
1435 CFRunLoopSourceRef source
= CFRunLoopSourceCreate(alloc
, 0, &ctxt
);
1436 _CFStreamSetSource(stream
, source
, FALSE
);
1437 CFRunLoopAddSource((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoopAndSourceKey
, 0), source
, (CFStringRef
)CFArrayGetValueAtIndex(runLoopAndSourceKey
, 1));
1438 CFRelease(runLoopAndSourceKey
);
1440 CFRunLoopAddSource(runLoop
, source
, runLoopMode
);
1444 /* We're not sharing, so just add the source to the rl & mode */
1445 CFRunLoopSourceRef source
= _CFStreamCopySource(stream
);
1447 CFRunLoopAddSource(runLoop
, source
, runLoopMode
);
1452 _CFStreamLock(stream
);
1453 if (!stream
->client
->runLoopsAndModes
) {
1454 stream
->client
->runLoopsAndModes
= CFArrayCreateMutable(CFGetAllocator(stream
), 0, &kCFTypeArrayCallBacks
);
1456 CFArrayAppendValue(stream
->client
->runLoopsAndModes
, runLoop
);
1457 CFArrayAppendValue(stream
->client
->runLoopsAndModes
, runLoopMode
);
1458 checkRLMArray(stream
->client
->runLoopsAndModes
);
1459 _CFStreamUnlock(stream
);
1462 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1463 cb
->schedule(stream
, runLoop
, runLoopMode
, _CFStreamGetInfoPointer(stream
));
1464 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1468 * If we've got events pending, we need to wake up and signal
1470 if (stream
->client
&& stream
->client
->whatToSignal
!= 0) {
1471 CFRunLoopSourceRef source
= _CFStreamCopySource(stream
);
1473 CFRunLoopSourceSignal(source
);
1475 _wakeUpRunLoop(stream
);
1480 CF_EXPORT
void CFReadStreamScheduleWithRunLoop(CFReadStreamRef stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1481 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID
, void, (NSInputStream
*)stream
, _scheduleInCFRunLoop
:runLoop forMode
:runLoopMode
);
1482 _CFStreamScheduleWithRunLoop((struct _CFStream
*)stream
, runLoop
, runLoopMode
);
1485 CF_EXPORT
void CFWriteStreamScheduleWithRunLoop(CFWriteStreamRef stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1486 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID
, void, (NSOutputStream
*)stream
, _scheduleInCFRunLoop
:runLoop forMode
:runLoopMode
);
1487 _CFStreamScheduleWithRunLoop((struct _CFStream
*)stream
, runLoop
, runLoopMode
);
1491 __private_extern__
void _CFStreamUnscheduleFromRunLoop(struct _CFStream
*stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1492 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1493 if (!stream
->client
) return;
1494 if (!stream
->client
->rlSource
) return;
1496 if (!__CFBitIsSet(stream
->flags
, SHARED_SOURCE
)) {
1497 CFRunLoopSourceRef source
= _CFStreamCopySource(stream
);
1499 CFRunLoopRemoveSource(runLoop
, source
, runLoopMode
);
1503 CFArrayRef runLoopAndSourceKey
;
1504 CFMutableArrayRef list
;
1507 __CFSpinLock(&sSourceLock
);
1509 runLoopAndSourceKey
= (CFArrayRef
)CFDictionaryGetValue(sSharedSources
, stream
);
1510 list
= (CFMutableArrayRef
)CFDictionaryGetValue(sSharedSources
, runLoopAndSourceKey
);
1512 count
= CFArrayGetCount(list
);
1513 i
= CFArrayGetFirstIndexOfValue(list
, CFRangeMake(0, count
), stream
);
1514 if (i
!= kCFNotFound
) {
1515 CFArrayRemoveValueAtIndex(list
, i
);
1520 CFRunLoopSourceRef source
= _CFStreamCopySource(stream
);
1522 CFRunLoopRemoveSource(runLoop
, source
, runLoopMode
);
1525 CFDictionaryRemoveValue(sSharedSources
, runLoopAndSourceKey
);
1528 CFDictionaryRemoveValue(sSharedSources
, stream
);
1530 _CFStreamSetSource(stream
, NULL
, count
== 0);
1532 __CFBitClear(stream
->flags
, SHARED_SOURCE
);
1534 __CFSpinUnlock(&sSourceLock
);
1537 _CFStreamLock(stream
);
1538 _CFStreamRemoveRunLoopAndModeFromArray(stream
->client
->runLoopsAndModes
, runLoop
, runLoopMode
);
1539 checkRLMArray(stream
->client
->runLoopsAndModes
);
1540 _CFStreamUnlock(stream
);
1542 if (cb
->unschedule
) {
1543 cb
->unschedule(stream
, runLoop
, runLoopMode
, _CFStreamGetInfoPointer(stream
));
1547 CF_EXPORT
void CFReadStreamUnscheduleFromRunLoop(CFReadStreamRef stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1548 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID
, void, (NSInputStream
*)stream
, _unscheduleFromCFRunLoop
:runLoop forMode
:runLoopMode
);
1549 _CFStreamUnscheduleFromRunLoop((struct _CFStream
*)stream
, runLoop
, runLoopMode
);
1552 void CFWriteStreamUnscheduleFromRunLoop(CFWriteStreamRef stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1553 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID
, void, (NSOutputStream
*)stream
, _unscheduleFromCFRunLoop
:runLoop forMode
:runLoopMode
);
1554 _CFStreamUnscheduleFromRunLoop((struct _CFStream
*)stream
, runLoop
, runLoopMode
);
1557 static void waitForOpen(struct _CFStream
*stream
) {
1558 CFRunLoopRef runLoop
= CFRunLoopGetCurrent();
1559 CFStringRef privateMode
= CFSTR("_kCFStreamBlockingOpenMode");
1560 _CFStreamScheduleWithRunLoop(stream
, runLoop
, privateMode
);
1561 // 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....
1562 while (__CFStreamGetStatus(stream
) == kCFStreamStatusOpening
) {
1563 CFRunLoopRunInMode(privateMode
, 1e+20, TRUE
);
1565 _CFStreamUnscheduleFromRunLoop(stream
, runLoop
, privateMode
);
1568 CF_EXPORT CFArrayRef
_CFReadStreamGetRunLoopsAndModes(CFReadStreamRef readStream
) {
1569 return _CFStreamGetRunLoopsAndModes((struct _CFStream
*)readStream
);
1572 CF_EXPORT CFArrayRef
_CFWriteStreamGetRunLoopsAndModes(CFWriteStreamRef writeStream
) {
1573 return _CFStreamGetRunLoopsAndModes((struct _CFStream
*)writeStream
);
1576 CF_EXPORT CFArrayRef
_CFReadStreamCopyRunLoopsAndModes(CFReadStreamRef readStream
) {
1577 return _CFStreamCopyRunLoopsAndModes((struct _CFStream
*)readStream
);
1580 CF_EXPORT CFArrayRef
_CFWriteStreamCopyRunLoopsAndModes(CFWriteStreamRef writeStream
) {
1581 return _CFStreamCopyRunLoopsAndModes((struct _CFStream
*)writeStream
);
1584 CF_EXPORT
void CFReadStreamSignalEvent(CFReadStreamRef stream
, CFStreamEventType event
, const void *error
) {
1585 _CFStreamSignalEvent((struct _CFStream
*)stream
, event
, (CFErrorRef
)error
, TRUE
);
1588 CF_EXPORT
void CFWriteStreamSignalEvent(CFWriteStreamRef stream
, CFStreamEventType event
, const void *error
) {
1589 _CFStreamSignalEvent((struct _CFStream
*)stream
, event
, (CFErrorRef
)error
, TRUE
);
1592 CF_EXPORT
void _CFReadStreamSignalEventDelayed(CFReadStreamRef stream
, CFStreamEventType event
, const void *error
) {
1593 _CFStreamSignalEvent((struct _CFStream
*)stream
, event
, (CFErrorRef
)error
, FALSE
);
1596 CF_EXPORT
void _CFReadStreamClearEvent(CFReadStreamRef readStream
, CFStreamEventType event
) {
1597 struct _CFStream
*stream
= (struct _CFStream
*)readStream
;
1598 if (stream
->client
) {
1599 stream
->client
->whatToSignal
&= ~event
;
1603 CF_EXPORT
void _CFWriteStreamSignalEventDelayed(CFWriteStreamRef stream
, CFStreamEventType event
, const void *error
) {
1604 _CFStreamSignalEvent((struct _CFStream
*)stream
, event
, (CFErrorRef
)error
, FALSE
);
1607 CF_EXPORT
void *CFReadStreamGetInfoPointer(CFReadStreamRef stream
) {
1608 return _CFStreamGetInfoPointer((struct _CFStream
*)stream
);
1611 CF_EXPORT
void *CFWriteStreamGetInfoPointer(CFWriteStreamRef stream
) {
1612 return _CFStreamGetInfoPointer((struct _CFStream
*)stream
);
1616 void _CFStreamSourceScheduleWithRunLoop(CFRunLoopSourceRef source
, CFMutableArrayRef runLoopsAndModes
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
)
1621 checkRLMArray(runLoopsAndModes
);
1623 count
= CFArrayGetCount(runLoopsAndModes
);
1624 range
= CFRangeMake(0, count
);
1626 while (range
.length
) {
1628 CFIndex i
= CFArrayGetFirstIndexOfValue(runLoopsAndModes
, range
, runLoop
);
1630 if (i
== kCFNotFound
)
1633 if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes
, i
+ 1), runLoopMode
))
1636 range
.location
= i
+ 2;
1637 range
.length
= count
- range
.location
;
1640 // Add the new values.
1641 CFArrayAppendValue(runLoopsAndModes
, runLoop
);
1642 CFArrayAppendValue(runLoopsAndModes
, runLoopMode
);
1644 // Schedule the source on the new loop and mode.
1646 CFRunLoopAddSource(runLoop
, source
, runLoopMode
);
1651 void _CFStreamSourceUnscheduleFromRunLoop(CFRunLoopSourceRef source
, CFMutableArrayRef runLoopsAndModes
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
)
1656 count
= CFArrayGetCount(runLoopsAndModes
);
1657 range
= CFRangeMake(0, count
);
1659 checkRLMArray(runLoopsAndModes
);
1661 while (range
.length
) {
1663 CFIndex i
= CFArrayGetFirstIndexOfValue(runLoopsAndModes
, range
, runLoop
);
1665 // If not found, it's not scheduled on it.
1666 if (i
== kCFNotFound
)
1669 // Make sure it is scheduled in this mode.
1670 if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes
, i
+ 1), runLoopMode
)) {
1672 // Remove mode and runloop from the list.
1673 CFArrayReplaceValues(runLoopsAndModes
, CFRangeMake(i
, 2), NULL
, 0);
1675 // Remove it from the runloop.
1677 CFRunLoopRemoveSource(runLoop
, source
, runLoopMode
);
1682 range
.location
= i
+ 2;
1683 range
.length
= count
- range
.location
;
1689 void _CFStreamSourceScheduleWithAllRunLoops(CFRunLoopSourceRef source
, CFArrayRef runLoopsAndModes
)
1691 CFIndex i
, count
= CFArrayGetCount(runLoopsAndModes
);
1696 checkRLMArray(runLoopsAndModes
);
1698 for (i
= 0; i
< count
; i
+= 2) {
1700 // Make sure it's scheduled on all the right loops and modes.
1701 // Go through the array adding the source to all loops and modes.
1702 CFRunLoopAddSource((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoopsAndModes
, i
),
1704 (CFStringRef
)CFArrayGetValueAtIndex(runLoopsAndModes
, i
+ 1));
1710 void _CFStreamSourceUncheduleFromAllRunLoops(CFRunLoopSourceRef source
, CFArrayRef runLoopsAndModes
)
1712 CFIndex i
, count
= CFArrayGetCount(runLoopsAndModes
);
1717 checkRLMArray(runLoopsAndModes
);
1719 for (i
= 0; i
< count
; i
+= 2) {
1721 // Go through the array removing the source from all loops and modes.
1722 CFRunLoopRemoveSource((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoopsAndModes
, i
),
1724 (CFStringRef
)CFArrayGetValueAtIndex(runLoopsAndModes
, i
+ 1));
1728 Boolean
_CFStreamRemoveRunLoopAndModeFromArray(CFMutableArrayRef runLoopsAndModes
, CFRunLoopRef rl
, CFStringRef mode
) {
1730 Boolean found
= FALSE
;
1732 if (!runLoopsAndModes
) return FALSE
;
1734 checkRLMArray(runLoopsAndModes
);
1736 cnt
= CFArrayGetCount(runLoopsAndModes
);
1737 for (idx
= 0; idx
+ 1 < cnt
; idx
+= 2) {
1738 if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes
, idx
), rl
) && CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes
, idx
+ 1), mode
)) {
1739 CFArrayRemoveValueAtIndex(runLoopsAndModes
, idx
);
1740 CFArrayRemoveValueAtIndex(runLoopsAndModes
, idx
);
1748 // Used by NSStream to properly allocate the bridged objects
1749 CF_EXPORT CFIndex
_CFStreamInstanceSize(void) {
1750 return sizeof(struct _CFStream
);
1753 #if DEPLOYMENT_TARGET_WINDOWS
1754 void __CFStreamCleanup(void) {
1755 __CFSpinLock(&sSourceLock
);
1756 if (sSharedSources
) {
1757 CFIndex count
= CFDictionaryGetCount(sSharedSources
);
1759 // Only release if empty. If it's still holding streams (which would be a client
1760 // bug leak), freeing this dict would free the streams, which then need to access the
1761 // dict to remove themselves, which leads to a deadlock.
1762 CFRelease(sSharedSources
);
1763 sSharedSources
= NULL
;
1765 const void ** keys
= (const void **)malloc(sizeof(const void *) * count
);
1769 CFDictionaryGetKeysAndValues(sSharedSources
, keys
, NULL
);
1770 fprintf(stderr
, "*** CFNetwork is shutting down, but %ld streams are still scheduled.\n", count
);
1772 for (i
= 0; i
< count
;i
++) {
1773 if ((CFGetTypeID(keys
[i
]) == __kCFReadStreamTypeID
) || (CFGetTypeID(keys
[i
]) == __kCFWriteStreamTypeID
)) {
1780 __CFSpinUnlock(&sSourceLock
);