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-2011, 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 CFSpinLock_t streamLock
;
42 CFArrayRef previousRunloopsAndModes
;
46 MIN_STATUS_CODE_BIT
= 0,
48 MAX_STATUS_CODE_BIT
= 4,
50 CONSTANT_CALLBACKS
= 5,
51 CALLING_CLIENT
= 6, // MUST remain 6 since it's value is used elsewhere.
55 // Values above used to be defined and others may rely on their values
57 // Values below should not matter if they are re-ordered or shift
63 /* 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
64 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 */
65 // Used in CFNetwork too
67 /* sSharesSources holds two mappings, one the inverse of the other, between a stream and the
68 RunLoop+RunLoopMode pair that it's scheduled in. If the stream is scheduled in more than
69 one loop or mode, it can't share RunLoopSources with others, and is not in this dict.
71 static CFSpinLock_t sSourceLock
= CFSpinLockInit
;
72 static CFMutableDictionaryRef sSharedSources
= NULL
;
74 static CFTypeID __kCFReadStreamTypeID
= _kCFRuntimeNotATypeID
;
75 static CFTypeID __kCFWriteStreamTypeID
= _kCFRuntimeNotATypeID
;
77 // Just reads the bits, for those cases where we don't want to go through any callback checking
78 #define __CFStreamGetStatus(x) __CFBitfieldGetValue((x)->flags, MAX_STATUS_CODE_BIT, MIN_STATUS_CODE_BIT)
80 __private_extern__ CFStreamStatus
_CFStreamGetStatus(struct _CFStream
*stream
);
81 static Boolean
_CFStreamRemoveRunLoopAndModeFromArray(CFMutableArrayRef runLoopsAndModes
, CFRunLoopRef rl
, CFStringRef mode
);
82 static void _wakeUpRunLoop(struct _CFStream
*stream
);
84 CF_INLINE
void checkRLMArray(CFArrayRef arr
)
87 assert(arr
== NULL
|| (CFArrayGetCount(arr
) % 2) == 0);
91 CF_INLINE
void* _CFStreamCreateReserved(CFAllocatorRef alloc
) {
92 struct CFStreamAux
* aux
= (struct CFStreamAux
*) CFAllocatorAllocate(alloc
, sizeof(struct CFStreamAux
), 0);
94 aux
->streamLock
= CFSpinLockInit
;
95 aux
->previousRunloopsAndModes
= NULL
;
100 CF_INLINE
void _CFStreamDestroyReserved(CFAllocatorRef alloc
, void* aux
) {
101 struct CFStreamAux
* paux
= (struct CFStreamAux
*) aux
;
102 if (paux
->previousRunloopsAndModes
)
103 CFRelease(paux
->previousRunloopsAndModes
);
104 CFAllocatorDeallocate(alloc
, aux
);
107 CF_INLINE
struct CFStreamAux
* _CFStreamGetAuxRecord(struct _CFStream
* stream
) {
108 return (struct CFStreamAux
*) stream
->_reserved1
;
111 CF_INLINE
void _CFStreamLock(struct _CFStream
* stream
) {
112 __CFSpinLock(&_CFStreamGetAuxRecord(stream
)->streamLock
);
115 CF_INLINE
void _CFStreamUnlock(struct _CFStream
* stream
) {
116 __CFSpinUnlock(&_CFStreamGetAuxRecord(stream
)->streamLock
);
119 CF_INLINE CFRunLoopSourceRef
_CFStreamCopySource(struct _CFStream
* stream
) {
120 CFRunLoopSourceRef source
= NULL
;
123 _CFStreamLock(stream
);
126 source
= stream
->client
->rlSource
;
131 _CFStreamUnlock(stream
);
137 CF_INLINE
void _CFStreamSetSource(struct _CFStream
* stream
, CFRunLoopSourceRef source
, Boolean invalidateOldSource
) {
138 CFRunLoopSourceRef oldSource
= NULL
;
141 _CFStreamLock(stream
);
142 if (stream
->client
) {
143 oldSource
= stream
->client
->rlSource
;
144 if (oldSource
!= NULL
)
147 stream
->client
->rlSource
= source
;
151 _CFStreamUnlock(stream
);
155 // Lose our extra retain
156 CFRelease(oldSource
);
158 if (invalidateOldSource
)
159 CFRunLoopSourceInvalidate(oldSource
);
161 // And lose the one that held it in our stream as well
162 CFRelease(oldSource
);
166 CF_INLINE
const struct _CFStreamCallBacks
*_CFStreamGetCallBackPtr(struct _CFStream
*stream
) {
167 return stream
->callBacks
;
170 CF_INLINE
void _CFStreamSetStatusCode(struct _CFStream
*stream
, CFStreamStatus newStatus
) {
171 CFStreamStatus status
= __CFStreamGetStatus(stream
);
172 if (((status
!= kCFStreamStatusClosed
) && (status
!= kCFStreamStatusError
)) ||
173 ((status
== kCFStreamStatusClosed
) && (newStatus
== kCFStreamStatusError
)))
175 __CFBitfieldSetValue(stream
->flags
, MAX_STATUS_CODE_BIT
, MIN_STATUS_CODE_BIT
, newStatus
);
179 CF_INLINE
void _CFStreamScheduleEvent(struct _CFStream
*stream
, CFStreamEventType event
) {
180 if (stream
->client
&& (stream
->client
->when
& event
)) {
181 CFRunLoopSourceRef source
= _CFStreamCopySource(stream
);
183 stream
->client
->whatToSignal
|= event
;
185 CFRunLoopSourceSignal(source
);
187 _wakeUpRunLoop(stream
);
192 CF_INLINE
void _CFStreamSetStreamError(struct _CFStream
*stream
, CFStreamError
*err
) {
193 if (!stream
->error
) {
194 stream
->error
= (CFErrorRef
)CFAllocatorAllocate(CFGetAllocator(stream
), sizeof(CFStreamError
), 0);
196 memmove(stream
->error
, err
, sizeof(CFStreamError
));
199 static CFStringRef
__CFStreamCopyDescription(CFTypeRef cf
) {
200 struct _CFStream
*stream
= (struct _CFStream
*)cf
;
201 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
202 CFStringRef contextDescription
;
204 if (cb
->copyDescription
) {
205 if (cb
->version
== 0) {
206 contextDescription
= ((CFStringRef(*)(void *))cb
->copyDescription
)(_CFStreamGetInfoPointer(stream
));
208 contextDescription
= cb
->copyDescription(stream
, _CFStreamGetInfoPointer(stream
));
211 contextDescription
= CFStringCreateWithFormat(CFGetAllocator(stream
), NULL
, CFSTR("info = %p"), _CFStreamGetInfoPointer(stream
));
213 if (CFGetTypeID(cf
) == __kCFReadStreamTypeID
) {
214 desc
= CFStringCreateWithFormat(CFGetAllocator(stream
), NULL
, CFSTR("<CFReadStream %p>{%@}"), stream
, contextDescription
);
216 desc
= CFStringCreateWithFormat(CFGetAllocator(stream
), NULL
, CFSTR("<CFWriteStream %p>{%@}"), stream
, contextDescription
);
218 CFRelease(contextDescription
);
222 static void _CFStreamDetachSource(struct _CFStream
* stream
) {
223 if (stream
&& stream
->client
&& stream
->client
->rlSource
) {
224 if (!__CFBitIsSet(stream
->flags
, SHARED_SOURCE
)) {
225 _CFStreamSetSource(stream
, NULL
, TRUE
);
229 CFArrayRef runLoopAndSourceKey
;
230 CFMutableArrayRef list
;
234 __CFSpinLock(&sSourceLock
);
236 runLoopAndSourceKey
= (CFArrayRef
)CFDictionaryGetValue(sSharedSources
, stream
);
237 list
= (CFMutableArrayRef
)CFDictionaryGetValue(sSharedSources
, runLoopAndSourceKey
);
239 count
= CFArrayGetCount(list
);
240 i
= CFArrayGetFirstIndexOfValue(list
, CFRangeMake(0, count
), stream
);
241 if (i
!= kCFNotFound
) {
242 CFArrayRemoveValueAtIndex(list
, i
);
246 CFAssert(CFArrayGetFirstIndexOfValue(list
, CFRangeMake(0, CFArrayGetCount(list
)), stream
) == kCFNotFound
, __kCFLogAssertion
, "CFStreamClose: stream found twice in its shared source's list");
249 CFRunLoopSourceRef source
= _CFStreamCopySource(stream
);
251 CFRunLoopRemoveSource((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoopAndSourceKey
, 0), source
, (CFStringRef
)CFArrayGetValueAtIndex(runLoopAndSourceKey
, 1));
254 CFDictionaryRemoveValue(sSharedSources
, runLoopAndSourceKey
);
257 CFDictionaryRemoveValue(sSharedSources
, stream
);
259 _CFStreamSetSource(stream
, NULL
, count
== 0);
261 __CFBitClear(stream
->flags
, SHARED_SOURCE
);
263 __CFSpinUnlock(&sSourceLock
);
268 __private_extern__
void _CFStreamClose(struct _CFStream
*stream
) {
269 CFStreamStatus status
= _CFStreamGetStatus(stream
);
270 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
271 if (status
== kCFStreamStatusNotOpen
|| status
== kCFStreamStatusClosed
|| (status
== kCFStreamStatusError
&& __CFBitIsSet(stream
->flags
, HAVE_CLOSED
))) {
272 // Stream is not open from the client's perspective; do not callout and do not update our status to "closed"
275 __CFBitSet(stream
->flags
, HAVE_CLOSED
);
276 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
278 cb
->close(stream
, _CFStreamGetInfoPointer(stream
));
280 if (stream
->client
) {
281 _CFStreamDetachSource(stream
);
283 _CFStreamSetStatusCode(stream
, kCFStreamStatusClosed
);
284 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
287 //static int numStreamInstances = 0;
289 static void __CFStreamDeallocate(CFTypeRef cf
) {
290 struct _CFStream
*stream
= (struct _CFStream
*)cf
;
291 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
292 CFAllocatorRef alloc
= CFGetAllocator(stream
);
293 // numStreamInstances --;
296 _CFStreamClose(stream
);
298 if (stream
->client
) {
299 CFStreamClientContext
*cbContext
;
300 cbContext
= &(stream
->client
->cbContext
);
301 if (cbContext
->info
&& cbContext
->release
) {
302 cbContext
->release(cbContext
->info
);
304 _CFStreamDetachSource(stream
);
305 if (stream
->client
->runLoopsAndModes
) {
306 CFRelease(stream
->client
->runLoopsAndModes
);
309 CFAllocatorDeallocate(alloc
, stream
->client
);
310 stream
->client
= NULL
; // Just in case finalize, below, calls back in to us
313 if (cb
->version
== 0) {
314 ((void(*)(void *))cb
->finalize
)(_CFStreamGetInfoPointer(stream
));
316 cb
->finalize(stream
, _CFStreamGetInfoPointer(stream
));
320 if (cb
->version
< 2) {
321 CFAllocatorDeallocate(alloc
, stream
->error
);
323 CFRelease(stream
->error
);
326 if (!__CFBitIsSet(stream
->flags
, CONSTANT_CALLBACKS
)) {
327 CFAllocatorDeallocate(alloc
, (void *)stream
->callBacks
);
329 if (stream
->_reserved1
)
330 _CFStreamDestroyReserved(alloc
, stream
->_reserved1
);
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 __private_extern__
void __CFStreamInitialize(void) {
364 __kCFReadStreamTypeID
= _CFRuntimeRegisterClass(&__CFReadStreamClass
);
365 __kCFWriteStreamTypeID
= _CFRuntimeRegisterClass(&__CFWriteStreamClass
);
369 CF_EXPORT CFTypeID
CFReadStreamGetTypeID(void) {
370 return __kCFReadStreamTypeID
;
373 CF_EXPORT CFTypeID
CFWriteStreamGetTypeID(void) {
374 return __kCFWriteStreamTypeID
;
377 static struct _CFStream
*_CFStreamCreate(CFAllocatorRef allocator
, Boolean isReadStream
) {
378 struct _CFStream
*newStream
= (struct _CFStream
*)_CFRuntimeCreateInstance(allocator
, isReadStream
? __kCFReadStreamTypeID
: __kCFWriteStreamTypeID
, sizeof(struct _CFStream
) - sizeof(CFRuntimeBase
), NULL
);
380 // numStreamInstances ++;
381 newStream
->flags
= 0;
382 _CFStreamSetStatusCode(newStream
, kCFStreamStatusNotOpen
);
383 newStream
->error
= NULL
;
384 newStream
->client
= NULL
;
385 newStream
->info
= NULL
;
386 newStream
->callBacks
= NULL
;
388 newStream
->_reserved1
= _CFStreamCreateReserved(allocator
);
393 __private_extern__
struct _CFStream
*_CFStreamCreateWithConstantCallbacks(CFAllocatorRef alloc
, void *info
, const struct _CFStreamCallBacks
*cb
, Boolean isReading
) {
394 struct _CFStream
*newStream
;
395 if (cb
->version
!= 1) return NULL
;
396 newStream
= _CFStreamCreate(alloc
, isReading
);
398 __CFBitSet(newStream
->flags
, CONSTANT_CALLBACKS
);
399 newStream
->callBacks
= cb
;
401 newStream
->info
= cb
->create(newStream
, info
);
403 newStream
->info
= info
;
409 CF_EXPORT
void _CFStreamSetInfoPointer(struct _CFStream
*stream
, void *info
, const struct _CFStreamCallBacks
*cb
) {
410 if (info
!= stream
->info
) {
411 if (stream
->callBacks
->finalize
) {
412 stream
->callBacks
->finalize(stream
, stream
->info
);
415 stream
->info
= cb
->create(stream
, info
);
420 stream
->callBacks
= cb
;
424 CF_EXPORT CFReadStreamRef
CFReadStreamCreate(CFAllocatorRef alloc
, const CFReadStreamCallBacks
*callbacks
, void *info
) {
425 struct _CFStream
*newStream
= _CFStreamCreate(alloc
, TRUE
);
426 struct _CFStreamCallBacks
*cb
;
427 if (!newStream
) return NULL
;
428 cb
= (struct _CFStreamCallBacks
*)CFAllocatorAllocate(alloc
, sizeof(struct _CFStreamCallBacks
), 0);
430 CFRelease(newStream
);
433 if (callbacks
->version
== 0) {
434 CFReadStreamCallBacksV0
*cbV0
= (CFReadStreamCallBacksV0
*)callbacks
;
435 CFStreamClientContext
*ctxt
= (CFStreamClientContext
*)info
;
436 newStream
->info
= ctxt
->retain
? (void *)ctxt
->retain(ctxt
->info
) : ctxt
->info
;
438 cb
->create
= (void *(*)(struct _CFStream
*, void *))ctxt
->retain
;
439 cb
->finalize
= (void(*)(struct _CFStream
*, void *))ctxt
->release
;
440 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))ctxt
->copyDescription
;
441 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))cbV0
->open
;
442 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))cbV0
->openCompleted
;
443 cb
->read
= (CFIndex (*)(CFReadStreamRef
, UInt8
*, CFIndex
, CFErrorRef
*, Boolean
*, void *))cbV0
->read
;
444 cb
->getBuffer
= (const UInt8
*(*)(CFReadStreamRef
, CFIndex
, CFIndex
*, CFErrorRef
*, Boolean
*, void *))cbV0
->getBuffer
;
445 cb
->canRead
= (Boolean (*)(CFReadStreamRef
, CFErrorRef
*, void*))cbV0
->canRead
;
448 cb
->close
= (void (*)(struct _CFStream
*, void *))cbV0
->close
;
449 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))cbV0
->copyProperty
;
450 cb
->setProperty
= NULL
;
451 cb
->requestEvents
= NULL
;
452 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV0
->schedule
;
453 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV0
->unschedule
;
454 } else if (callbacks
->version
== 1) {
455 CFReadStreamCallBacksV1
*cbV1
= (CFReadStreamCallBacksV1
*)callbacks
;
456 newStream
->info
= cbV1
->create
? cbV1
->create((CFReadStreamRef
)newStream
, info
) : info
;
458 cb
->create
= (void *(*)(struct _CFStream
*, void *))cbV1
->create
;
459 cb
->finalize
= (void(*)(struct _CFStream
*, void *))cbV1
->finalize
;
460 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))cbV1
->copyDescription
;
461 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))cbV1
->open
;
462 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))cbV1
->openCompleted
;
463 cb
->read
= (CFIndex (*)(CFReadStreamRef
, UInt8
*, CFIndex
, CFErrorRef
*, Boolean
*, void *))cbV1
->read
;
464 cb
->getBuffer
= (const UInt8
*(*)(CFReadStreamRef
, CFIndex
, CFIndex
*, CFErrorRef
*, Boolean
*, void *))cbV1
->getBuffer
;
465 cb
->canRead
= (Boolean (*)(CFReadStreamRef
, CFErrorRef
*, void*))cbV1
->canRead
;
468 cb
->close
= (void (*)(struct _CFStream
*, void *))cbV1
->close
;
469 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))cbV1
->copyProperty
;
470 cb
->setProperty
= (Boolean(*)(struct _CFStream
*, CFStringRef
, CFTypeRef
, void *))cbV1
->setProperty
;
471 cb
->requestEvents
= (void(*)(struct _CFStream
*, CFOptionFlags
, void *))cbV1
->requestEvents
;
472 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV1
->schedule
;
473 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV1
->unschedule
;
475 newStream
->info
= callbacks
->create
? callbacks
->create((CFReadStreamRef
)newStream
, info
) : info
;
477 cb
->create
= (void *(*)(struct _CFStream
*, void *))callbacks
->create
;
478 cb
->finalize
= (void(*)(struct _CFStream
*, void *))callbacks
->finalize
;
479 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))callbacks
->copyDescription
;
480 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))callbacks
->open
;
481 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))callbacks
->openCompleted
;
482 cb
->read
= callbacks
->read
;
483 cb
->getBuffer
= callbacks
->getBuffer
;
484 cb
->canRead
= callbacks
->canRead
;
487 cb
->close
= (void (*)(struct _CFStream
*, void *))callbacks
->close
;
488 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))callbacks
->copyProperty
;
489 cb
->setProperty
= (Boolean(*)(struct _CFStream
*, CFStringRef
, CFTypeRef
, void *))callbacks
->setProperty
;
490 cb
->requestEvents
= (void(*)(struct _CFStream
*, CFOptionFlags
, void *))callbacks
->requestEvents
;
491 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))callbacks
->schedule
;
492 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))callbacks
->unschedule
;
495 newStream
->callBacks
= cb
;
496 return (CFReadStreamRef
)newStream
;
499 CF_EXPORT CFWriteStreamRef
CFWriteStreamCreate(CFAllocatorRef alloc
, const CFWriteStreamCallBacks
*callbacks
, void *info
) {
500 struct _CFStream
*newStream
= _CFStreamCreate(alloc
, FALSE
);
501 struct _CFStreamCallBacks
*cb
;
502 if (!newStream
) return NULL
;
503 cb
= (struct _CFStreamCallBacks
*)CFAllocatorAllocate(alloc
, sizeof(struct _CFStreamCallBacks
), 0);
505 CFRelease(newStream
);
508 if (callbacks
->version
== 0) {
509 CFWriteStreamCallBacksV0
*cbV0
= (CFWriteStreamCallBacksV0
*)callbacks
;
510 CFStreamClientContext
*ctxt
= (CFStreamClientContext
*)info
;
511 newStream
->info
= ctxt
->retain
? (void *)ctxt
->retain(ctxt
->info
) : ctxt
->info
;
513 cb
->create
= (void *(*)(struct _CFStream
*, void *))ctxt
->retain
;
514 cb
->finalize
= (void(*)(struct _CFStream
*, void *))ctxt
->release
;
515 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))ctxt
->copyDescription
;
516 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))cbV0
->open
;
517 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))cbV0
->openCompleted
;
519 cb
->getBuffer
= NULL
;
521 cb
->write
= (CFIndex(*)(CFWriteStreamRef stream
, const UInt8
*buffer
, CFIndex bufferLength
, CFErrorRef
*error
, void *info
))cbV0
->write
;
522 cb
->canWrite
= (Boolean(*)(CFWriteStreamRef stream
, CFErrorRef
*error
, void *info
))cbV0
->canWrite
;
523 cb
->close
= (void (*)(struct _CFStream
*, void *))cbV0
->close
;
524 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))cbV0
->copyProperty
;
525 cb
->setProperty
= NULL
;
526 cb
->requestEvents
= NULL
;
527 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV0
->schedule
;
528 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV0
->unschedule
;
529 } else if (callbacks
->version
== 1) {
530 CFWriteStreamCallBacksV1
*cbV1
= (CFWriteStreamCallBacksV1
*)callbacks
;
532 newStream
->info
= cbV1
->create
? cbV1
->create((CFWriteStreamRef
)newStream
, info
) : info
;
533 cb
->create
= (void *(*)(struct _CFStream
*, void *))cbV1
->create
;
534 cb
->finalize
= (void(*)(struct _CFStream
*, void *))cbV1
->finalize
;
535 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))cbV1
->copyDescription
;
536 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))cbV1
->open
;
537 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))cbV1
->openCompleted
;
539 cb
->getBuffer
= NULL
;
541 cb
->write
= (CFIndex(*)(CFWriteStreamRef stream
, const UInt8
*buffer
, CFIndex bufferLength
, CFErrorRef
*error
, void *info
))cbV1
->write
;
542 cb
->canWrite
= (Boolean(*)(CFWriteStreamRef stream
, CFErrorRef
*error
, void *info
))cbV1
->canWrite
;
543 cb
->close
= (void (*)(struct _CFStream
*, void *))cbV1
->close
;
544 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))cbV1
->copyProperty
;
545 cb
->setProperty
= (Boolean (*)(struct _CFStream
*, CFStringRef
, CFTypeRef
, void *))cbV1
->setProperty
;
546 cb
->requestEvents
= (void(*)(struct _CFStream
*, CFOptionFlags
, void *))cbV1
->requestEvents
;
547 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV1
->schedule
;
548 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV1
->unschedule
;
550 cb
->version
= callbacks
->version
;
551 newStream
->info
= callbacks
->create
? callbacks
->create((CFWriteStreamRef
)newStream
, info
) : info
;
552 cb
->create
= (void *(*)(struct _CFStream
*, void *))callbacks
->create
;
553 cb
->finalize
= (void(*)(struct _CFStream
*, void *))callbacks
->finalize
;
554 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))callbacks
->copyDescription
;
555 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))callbacks
->open
;
556 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))callbacks
->openCompleted
;
558 cb
->getBuffer
= NULL
;
560 cb
->write
= callbacks
->write
;
561 cb
->canWrite
= callbacks
->canWrite
;
562 cb
->close
= (void (*)(struct _CFStream
*, void *))callbacks
->close
;
563 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))callbacks
->copyProperty
;
564 cb
->setProperty
= (Boolean (*)(struct _CFStream
*, CFStringRef
, CFTypeRef
, void *))callbacks
->setProperty
;
565 cb
->requestEvents
= (void(*)(struct _CFStream
*, CFOptionFlags
, void *))callbacks
->requestEvents
;
566 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))callbacks
->schedule
;
567 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))callbacks
->unschedule
;
569 newStream
->callBacks
= cb
;
570 return (CFWriteStreamRef
)newStream
;
573 static void _signalEventSync(struct _CFStream
* stream
, CFOptionFlags whatToSignal
)
575 CFOptionFlags eventMask
;
577 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
580 void (*release
) (void*) = NULL
;
582 if (stream
->client
->cbContext
.retain
== NULL
)
583 info
= stream
->client
->cbContext
.info
;
585 info
= stream
->client
->cbContext
.retain(stream
->client
->cbContext
.info
);
586 release
= stream
->client
->cbContext
.release
;
589 for (eventMask
= 1; eventMask
<= whatToSignal
; eventMask
= eventMask
<< 1) {
590 if ((eventMask
& whatToSignal
) && (stream
->client
->when
& eventMask
)) {
591 stream
->client
->cb(stream
, eventMask
, info
);
593 /* What happens if the callback sets the client to NULL? We're in a loop here... Hmm. */
594 /* After writing that comment, I see: <rdar://problem/6793636> CFReadStreamSetClient(..., NULL) unsafely releases info pointer immediately */
595 /* Of note, when the stream callbacks are set to to NULL, we're re-initalized so as not to receive more events, so we
596 * should break pout of this loop */
603 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
606 static void _cfstream_solo_signalEventSync(void* info
)
608 CFTypeID typeID
= CFGetTypeID((CFTypeRef
) info
);
610 if (typeID
!= CFReadStreamGetTypeID() && typeID
!= CFWriteStreamGetTypeID()) {
611 CFLog(__kCFLogAssertion
, CFSTR("Expected an read or write stream for %p"), info
);
616 struct _CFStream
* stream
= (struct _CFStream
*) info
;
617 CFOptionFlags whatToSignal
= stream
->client
->whatToSignal
;
618 stream
->client
->whatToSignal
= 0;
620 /* Since the array version holds a retain, we do it here as well, as opposed to taking a second retain in the client callback */
622 _signalEventSync(stream
, whatToSignal
);
627 static void _cfstream_shared_signalEventSync(void* info
)
629 CFTypeID typeID
= CFGetTypeID((CFTypeRef
) info
);
631 if (typeID
!= CFArrayGetTypeID()) {
632 CFLog(__kCFLogAssertion
, CFSTR("Expected an array for %p"), info
);
637 CFMutableArrayRef list
= (CFMutableArrayRef
) info
;
639 CFOptionFlags whatToSignal
= 0;
640 struct _CFStream
* stream
= NULL
;
642 __CFSpinLock(&sSourceLock
);
644 /* Looks like, we grab the first stream that wants an event... */
645 /* Note that I grab an extra retain when I pull out the stream here... */
646 c
= CFArrayGetCount(list
);
647 for (i
= 0; i
< c
; i
++) {
648 struct _CFStream
* s
= (struct _CFStream
*)CFArrayGetValueAtIndex(list
, i
);
650 if (s
->client
->whatToSignal
) {
653 whatToSignal
= stream
->client
->whatToSignal
;
654 s
->client
->whatToSignal
= 0;
659 /* And then we also signal any other streams in this array so that we get them next go? */
661 struct _CFStream
* s
= (struct _CFStream
*)CFArrayGetValueAtIndex(list
, i
);
662 if (s
->client
->whatToSignal
) {
663 CFRunLoopSourceRef source
= _CFStreamCopySource(s
);
665 CFRunLoopSourceSignal(source
);
672 __CFSpinUnlock(&sSourceLock
);
674 /* We're sitting here now, possibly with a stream that needs to be processed by the common routine */
676 _signalEventSync(stream
, whatToSignal
);
678 /* Lose our extra retain */
684 /* This routine is to be considered unsafe... */
685 static CFArrayRef
_CFStreamGetRunLoopsAndModes(struct _CFStream
*stream
)
687 CFArrayRef result
= NULL
;
688 if (stream
&& stream
->client
) {
689 _CFStreamLock(stream
);
690 struct CFStreamAux
* aux
= _CFStreamGetAuxRecord(stream
);
691 if (aux
->previousRunloopsAndModes
) {
692 CFRelease(aux
->previousRunloopsAndModes
);
693 aux
->previousRunloopsAndModes
= NULL
;
695 if (stream
->client
->runLoopsAndModes
) {
696 aux
->previousRunloopsAndModes
= CFArrayCreateCopy(CFGetAllocator(stream
), stream
->client
->runLoopsAndModes
);
698 result
= aux
->previousRunloopsAndModes
;
699 checkRLMArray(result
);
700 _CFStreamUnlock(stream
);
705 static CFArrayRef
_CFStreamCopyRunLoopsAndModes(struct _CFStream
*stream
)
707 CFArrayRef result
= NULL
;
708 if (stream
&& stream
->client
) {
709 _CFStreamLock(stream
);
710 if (stream
->client
->runLoopsAndModes
) {
711 result
= CFArrayCreateCopy(CFGetAllocator(stream
), stream
->client
->runLoopsAndModes
);
713 checkRLMArray(result
);
714 _CFStreamUnlock(stream
);
719 static void _wakeUpRunLoop(struct _CFStream
*stream
) {
720 CFArrayRef rlArray
= _CFStreamCopyRunLoopsAndModes(stream
);
722 CFIndex cnt
= CFArrayGetCount(rlArray
);
726 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, 0);
727 } else if (cnt
> 2) {
729 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, 0);
730 for (idx
= 2; NULL
!= rl
&& idx
< cnt
; idx
+=2) {
731 CFRunLoopRef value
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, idx
);
732 if (value
!= rl
) rl
= NULL
;
734 if (NULL
== rl
) { /* more than one different rl, so we must pick one */
735 for (idx
= 0; idx
< cnt
; idx
+=2) {
736 CFRunLoopRef value
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, idx
);
737 CFStringRef currentMode
= CFRunLoopCopyCurrentMode(value
);
738 if (NULL
!= currentMode
&& CFEqual(currentMode
, CFArrayGetValueAtIndex(rlArray
, idx
+1)) && CFRunLoopIsWaiting(value
)) {
739 CFRelease(currentMode
);
743 if (NULL
!= currentMode
) CFRelease(currentMode
);
745 if (NULL
== rl
) { /* didn't choose one above, so choose first */
746 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, 0);
750 if (NULL
!= rl
&& CFRunLoopIsWaiting(rl
))
756 __private_extern__
void _CFStreamSignalEvent(struct _CFStream
*stream
, CFStreamEventType event
, CFErrorRef error
, Boolean synchronousAllowed
) {
757 // Update our internal status; we must use the primitive __CFStreamGetStatus(), because CFStreamGetStatus() calls us, and we can end up in an infinite loop.
758 CFStreamStatus status
= __CFStreamGetStatus(stream
);
760 // Sanity check the event
761 if (status
== kCFStreamStatusNotOpen
) {
762 // No events allowed; this is almost certainly a bug in the stream's implementation
763 CFLog(__kCFLogAssertion
, CFSTR("Stream %p is sending an event before being opened"), stream
);
765 } else if (status
== kCFStreamStatusClosed
|| status
== kCFStreamStatusError
) {
766 // no further events are allowed
768 } else if (status
== kCFStreamStatusAtEnd
) {
769 // Only error events are allowed
770 event
&= kCFStreamEventErrorOccurred
;
771 } else if (status
!= kCFStreamStatusOpening
) {
772 // cannot send open completed; that happened already
773 event
&= ~kCFStreamEventOpenCompleted
;
776 // Change status if appropriate
777 if (event
& kCFStreamEventOpenCompleted
&& status
== kCFStreamStatusOpening
) {
778 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
780 if (event
& kCFStreamEventEndEncountered
&& status
< kCFStreamStatusAtEnd
) {
781 _CFStreamSetStatusCode(stream
, kCFStreamStatusAtEnd
);
783 if (event
& kCFStreamEventErrorOccurred
) {
784 if (_CFStreamGetCallBackPtr(stream
)->version
< 2) {
785 _CFStreamSetStreamError(stream
, (CFStreamError
*)error
);
787 CFAssert(error
, __kCFLogAssertion
, "CFStream: kCFStreamEventErrorOccurred signalled, but error is NULL!");
789 if (stream
->error
) CFRelease(stream
->error
);
790 stream
->error
= error
;
792 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
795 // Now signal any pertinent event
796 if (stream
->client
&& (stream
->client
->when
& event
) != 0) {
797 CFRunLoopSourceRef source
= _CFStreamCopySource(stream
);
800 Boolean signalNow
= FALSE
;
802 stream
->client
->whatToSignal
|= event
;
804 if (synchronousAllowed
&& !__CFBitIsSet(stream
->flags
, CALLING_CLIENT
)) {
806 CFRunLoopRef rl
= CFRunLoopGetCurrent();
807 CFStringRef mode
= CFRunLoopCopyCurrentMode(rl
);
810 if (CFRunLoopContainsSource(rl
, source
, mode
))
818 // Can call out safely right now
819 _cfstream_solo_signalEventSync(stream
);
821 // Schedule for later delivery
823 CFRunLoopSourceSignal(source
);
825 _wakeUpRunLoop(stream
);
833 __private_extern__ CFStreamStatus
_CFStreamGetStatus(struct _CFStream
*stream
) {
834 CFStreamStatus status
= __CFStreamGetStatus(stream
);
835 // 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.
836 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
837 if (status
== kCFStreamStatusOpening
) {
838 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
839 if (cb
->openCompleted
) {
841 if (cb
->version
< 2) {
842 CFStreamError err
= {0, 0};
843 isComplete
= ((_CFStreamCBOpenCompletedV1
)(cb
->openCompleted
))(stream
, &err
, _CFStreamGetInfoPointer(stream
));
844 if (err
.error
!= 0) _CFStreamSetStreamError(stream
, &err
);
846 isComplete
= cb
->openCompleted(stream
, &(stream
->error
), _CFStreamGetInfoPointer(stream
));
849 if (!stream
->error
) {
850 status
= kCFStreamStatusOpen
;
852 status
= kCFStreamStatusError
;
854 _CFStreamSetStatusCode(stream
, status
);
855 if (status
== kCFStreamStatusOpen
) {
856 _CFStreamScheduleEvent(stream
, kCFStreamEventOpenCompleted
);
858 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
863 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
867 CF_EXPORT CFStreamStatus
CFReadStreamGetStatus(CFReadStreamRef stream
) {
868 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID
, CFStreamStatus
, stream
, "streamStatus");
869 return _CFStreamGetStatus((struct _CFStream
*)stream
);
872 CF_EXPORT CFStreamStatus
CFWriteStreamGetStatus(CFWriteStreamRef stream
) {
873 CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID
, CFStreamStatus
, stream
, "streamStatus");
874 return _CFStreamGetStatus((struct _CFStream
*)stream
);
877 static CFStreamError
_CFStreamGetStreamError(struct _CFStream
*stream
) {
878 CFStreamError result
;
879 if (!stream
->error
) {
882 } else if (_CFStreamGetCallBackPtr(stream
)->version
< 2) {
883 CFStreamError
*streamError
= (CFStreamError
*)(stream
->error
);
884 result
.error
= streamError
->error
;
885 result
.domain
= streamError
->domain
;
887 result
= _CFStreamErrorFromError(stream
->error
);
892 CF_EXPORT CFStreamError
CFReadStreamGetError(CFReadStreamRef stream
) {
893 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID
, CFStreamError
, stream
, "_cfStreamError");
894 return _CFStreamGetStreamError((struct _CFStream
*)stream
);
897 CF_EXPORT CFStreamError
CFWriteStreamGetError(CFWriteStreamRef stream
) {
898 CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID
, CFStreamError
, stream
, "_cfStreamError");
899 return _CFStreamGetStreamError((struct _CFStream
*)stream
);
902 static CFErrorRef
_CFStreamCopyError(struct _CFStream
*stream
) {
903 if (!stream
->error
) {
905 } else if (_CFStreamGetCallBackPtr(stream
)->version
< 2) {
906 return _CFErrorFromStreamError(CFGetAllocator(stream
), (CFStreamError
*)(stream
->error
));
908 CFRetain(stream
->error
);
909 return stream
->error
;
913 CF_EXPORT CFErrorRef
CFReadStreamCopyError(CFReadStreamRef stream
) {
914 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID
, CFErrorRef
, stream
, "streamError");
915 return _CFStreamCopyError((struct _CFStream
*)stream
);
918 CF_EXPORT CFErrorRef
CFWriteStreamCopyError(CFWriteStreamRef stream
) {
919 return _CFStreamCopyError((struct _CFStream
*)stream
);
920 CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID
, CFErrorRef
, stream
, "streamError");
923 __private_extern__ Boolean
_CFStreamOpen(struct _CFStream
*stream
) {
924 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
925 Boolean success
, openComplete
;
926 if (_CFStreamGetStatus(stream
) != kCFStreamStatusNotOpen
) {
929 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
930 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpening
);
932 if (cb
->version
< 2) {
933 CFStreamError err
= {0, 0};
934 success
= ((_CFStreamCBOpenV1
)(cb
->open
))(stream
, &err
, &openComplete
, _CFStreamGetInfoPointer(stream
));
935 if (err
.error
!= 0) _CFStreamSetStreamError(stream
, &err
);
937 success
= cb
->open(stream
, &(stream
->error
), &openComplete
, _CFStreamGetInfoPointer(stream
));
945 // 2957690 - Guard against the possibility that the stream has already signalled itself in to a later state (like AtEnd)
946 if (__CFStreamGetStatus(stream
) == kCFStreamStatusOpening
) {
947 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
949 _CFStreamScheduleEvent(stream
, kCFStreamEventOpenCompleted
);
951 #if DEPLOYMENT_TARGET_WINDOWS
952 _CFStreamClose(stream
);
954 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
955 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
958 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
962 CF_EXPORT Boolean
CFReadStreamOpen(CFReadStreamRef stream
) {
963 if(CF_IS_OBJC(__kCFReadStreamTypeID
, stream
)) {
964 CF_OBJC_VOIDCALL0(stream
, "open");
967 return _CFStreamOpen((struct _CFStream
*)stream
);
970 CF_EXPORT Boolean
CFWriteStreamOpen(CFWriteStreamRef stream
) {
971 if(CF_IS_OBJC(__kCFWriteStreamTypeID
, stream
)) {
972 CF_OBJC_VOIDCALL0(stream
, "open");
975 return _CFStreamOpen((struct _CFStream
*)stream
);
978 CF_EXPORT
void CFReadStreamClose(CFReadStreamRef stream
) {
979 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID
, void, stream
, "close");
980 _CFStreamClose((struct _CFStream
*)stream
);
983 CF_EXPORT
void CFWriteStreamClose(CFWriteStreamRef stream
) {
984 CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID
, void, stream
, "close");
985 _CFStreamClose((struct _CFStream
*)stream
);
988 CF_EXPORT Boolean
CFReadStreamHasBytesAvailable(CFReadStreamRef readStream
) {
989 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID
, Boolean
, readStream
, "hasBytesAvailable");
990 struct _CFStream
*stream
= (struct _CFStream
*)readStream
;
991 CFStreamStatus status
= _CFStreamGetStatus(stream
);
992 const struct _CFStreamCallBacks
*cb
;
993 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusReading
) {
996 cb
= _CFStreamGetCallBackPtr(stream
);
997 if (cb
->canRead
== NULL
) {
998 return TRUE
; // No way to know without trying....
1001 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1002 if (cb
->version
< 2) {
1003 result
= ((_CFStreamCBCanReadV1
)(cb
->canRead
))((CFReadStreamRef
)stream
, _CFStreamGetInfoPointer(stream
));
1005 result
= cb
->canRead((CFReadStreamRef
)stream
, &(stream
->error
), _CFStreamGetInfoPointer(stream
));
1006 if (stream
->error
) {
1007 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
1008 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
1011 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1016 static void waitForOpen(struct _CFStream
*stream
);
1017 CFIndex
CFReadStreamRead(CFReadStreamRef readStream
, UInt8
*buffer
, CFIndex bufferLength
) {
1018 CF_OBJC_FUNCDISPATCH2(__kCFReadStreamTypeID
, CFIndex
, readStream
, "read:maxLength:", buffer
, bufferLength
);
1019 struct _CFStream
*stream
= (struct _CFStream
*)readStream
;
1020 CFStreamStatus status
= _CFStreamGetStatus(stream
);
1021 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1022 if (status
== kCFStreamStatusOpening
) {
1023 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1024 waitForOpen(stream
);
1025 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1026 status
= _CFStreamGetStatus(stream
);
1029 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusReading
&& status
!= kCFStreamStatusAtEnd
) {
1031 } else if (status
== kCFStreamStatusAtEnd
) {
1036 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1037 if (stream
->client
) {
1038 stream
->client
->whatToSignal
&= ~kCFStreamEventHasBytesAvailable
;
1040 _CFStreamSetStatusCode(stream
, kCFStreamStatusReading
);
1041 if (cb
->version
< 2) {
1042 CFStreamError err
= {0, 0};
1043 bytesRead
= ((_CFStreamCBReadV1
)(cb
->read
))((CFReadStreamRef
)stream
, buffer
, bufferLength
, &err
, &atEOF
, _CFStreamGetInfoPointer(stream
));
1044 if (err
.error
!= 0) _CFStreamSetStreamError(stream
, &err
);
1046 bytesRead
= cb
->read((CFReadStreamRef
)stream
, buffer
, bufferLength
, &(stream
->error
), &atEOF
, _CFStreamGetInfoPointer(stream
));
1048 if (stream
->error
) {
1050 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
1051 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
1053 _CFStreamSetStatusCode(stream
, kCFStreamStatusAtEnd
);
1054 _CFStreamScheduleEvent(stream
, kCFStreamEventEndEncountered
);
1056 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
1058 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1063 CF_EXPORT
const UInt8
*CFReadStreamGetBuffer(CFReadStreamRef readStream
, CFIndex maxBytesToRead
, CFIndex
*numBytesRead
) {
1064 if (CF_IS_OBJC(__kCFReadStreamTypeID
, readStream
)) {
1065 uint8_t *bufPtr
= NULL
;
1067 CF_OBJC_CALL2(Boolean
, gotBytes
, readStream
, "getBuffer:length:", &bufPtr
, 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_FUNCDISPATCH0(__kCFWriteStreamTypeID
, Boolean
, 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_FUNCDISPATCH2(__kCFWriteStreamTypeID
, CFIndex
, writeStream
, "write:maxLength:", buffer
, 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_FUNCDISPATCH1(__kCFReadStreamTypeID
, CFTypeRef
, stream
, "propertyForKey:", propertyName
);
1208 return _CFStreamCopyProperty((struct _CFStream
*)stream
, propertyName
);
1211 CF_EXPORT CFTypeRef
CFWriteStreamCopyProperty(CFWriteStreamRef stream
, CFStringRef propertyName
) {
1212 CF_OBJC_FUNCDISPATCH1(__kCFWriteStreamTypeID
, CFTypeRef
, stream
, "propertyForKey:", 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_FUNCDISPATCH2(__kCFReadStreamTypeID
, Boolean
, stream
, "setProperty:forKey:", propertyValue
, propertyName
);
1232 return _CFStreamSetProperty((struct _CFStream
*)stream
, propertyName
, propertyValue
);
1236 Boolean
CFWriteStreamSetProperty(CFWriteStreamRef stream
, CFStringRef propertyName
, CFTypeRef propertyValue
) {
1237 CF_OBJC_FUNCDISPATCH2(__kCFWriteStreamTypeID
, Boolean
, stream
, "setProperty:forKey:", propertyValue
, 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_FUNCDISPATCH3(__kCFReadStreamTypeID
, Boolean
, readStream
, "_setCFClientFlags:callback:context:", streamEvents
, clientCB
, 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_FUNCDISPATCH3(__kCFWriteStreamTypeID
, Boolean
, writeStream
, "_setCFClientFlags:callback:context:", streamEvents
, clientCB
, 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_FUNCDISPATCH2(__kCFReadStreamTypeID
, void, stream
, "_scheduleInCFRunLoop:forMode:", runLoop
, runLoopMode
);
1482 _CFStreamScheduleWithRunLoop((struct _CFStream
*)stream
, runLoop
, runLoopMode
);
1485 CF_EXPORT
void CFWriteStreamScheduleWithRunLoop(CFWriteStreamRef stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1486 CF_OBJC_FUNCDISPATCH2(__kCFWriteStreamTypeID
, void, stream
, "_scheduleInCFRunLoop:forMode:", runLoop
, 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_FUNCDISPATCH2(__kCFReadStreamTypeID
, void, stream
, "_unscheduleFromCFRunLoop:forMode:", runLoop
, runLoopMode
);
1549 _CFStreamUnscheduleFromRunLoop((struct _CFStream
*)stream
, runLoop
, runLoopMode
);
1552 void CFWriteStreamUnscheduleFromRunLoop(CFWriteStreamRef stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1553 CF_OBJC_FUNCDISPATCH2(__kCFWriteStreamTypeID
, void, stream
, "_unscheduleFromCFRunLoop:forMode:", runLoop
, 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_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1754 #elif DEPLOYMENT_TARGET_WINDOWS
1755 void __CFStreamCleanup(void) {
1756 __CFSpinLock(&sSourceLock
);
1757 if (sSharedSources
) {
1758 CFIndex count
= CFDictionaryGetCount(sSharedSources
);
1760 // Only release if empty. If it's still holding streams (which would be a client
1761 // bug leak), freeing this dict would free the streams, which then need to access the
1762 // dict to remove themselves, which leads to a deadlock.
1763 CFRelease(sSharedSources
);
1764 sSharedSources
= NULL
;
1766 const void ** keys
= (const void **)malloc(sizeof(const void *) * count
);
1770 CFDictionaryGetKeysAndValues(sSharedSources
, keys
, NULL
);
1771 fprintf(stderr
, "*** CFNetwork is shutting down, but %ld streams are still scheduled.\n", count
);
1773 for (i
= 0; i
< count
;i
++) {
1774 if ((CFGetTypeID(keys
[i
]) == __kCFReadStreamTypeID
) || (CFGetTypeID(keys
[i
]) == __kCFWriteStreamTypeID
)) {
1781 __CFSpinUnlock(&sSourceLock
);
1784 #error Unknown or unspecified DEPLOYMENT_TARGET