2 * Copyright (c) 2010 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-2009, Apple Inc. All rights reserved.
26 Responsibility: Becky Willrich
29 #include <CoreFoundation/CFRuntime.h>
30 #include <CoreFoundation/CFNumber.h>
32 #include "CFStreamInternal.h"
33 #include "CFInternal.h"
37 CFSpinLock_t streamLock
;
41 MIN_STATUS_CODE_BIT
= 0,
43 MAX_STATUS_CODE_BIT
= 4,
45 CONSTANT_CALLBACKS
= 5,
46 CALLING_CLIENT
= 6, // MUST remain 6 since it's value is used elsewhere.
50 // Values above used to be defined and others may rely on their values
52 // Values below should not matter if they are re-ordered or shift
58 /* 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
59 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 */
60 // Used in CFNetwork too
62 /* sSharesSources holds two mappings, one the inverse of the other, between a stream and the
63 RunLoop+RunLoopMode pair that it's scheduled in. If the stream is scheduled in more than
64 one loop or mode, it can't share RunLoopSources with others, and is not in this dict.
66 static CFSpinLock_t sSourceLock
= CFSpinLockInit
;
67 static CFMutableDictionaryRef sSharedSources
= NULL
;
69 static CFTypeID __kCFReadStreamTypeID
= _kCFRuntimeNotATypeID
;
70 static CFTypeID __kCFWriteStreamTypeID
= _kCFRuntimeNotATypeID
;
72 // Just reads the bits, for those cases where we don't want to go through any callback checking
73 #define __CFStreamGetStatus(x) __CFBitfieldGetValue((x)->flags, MAX_STATUS_CODE_BIT, MIN_STATUS_CODE_BIT)
75 __private_extern__ CFStreamStatus
_CFStreamGetStatus(struct _CFStream
*stream
);
76 static Boolean
_CFStreamRemoveRunLoopAndModeFromArray(CFMutableArrayRef runLoopsAndModes
, CFRunLoopRef rl
, CFStringRef mode
);
77 static void _wakeUpRunLoop(struct _CFStream
*stream
);
79 CF_INLINE
void* _CFStreamCreateReserved(CFAllocatorRef alloc
) {
80 struct CFStreamAux
* aux
= (struct CFStreamAux
*) CFAllocatorAllocate(alloc
, sizeof(struct CFStreamAux
), 0);
82 aux
->streamLock
= CFSpinLockInit
;
87 CF_INLINE
void _CFStreamDestroyReserved(CFAllocatorRef alloc
, void* aux
) {
88 CFAllocatorDeallocate(alloc
, aux
);
91 CF_INLINE
struct CFStreamAux
* _CFStreamGetAuxRecord(struct _CFStream
* stream
) {
92 return (struct CFStreamAux
*) stream
->_reserved1
;
95 CF_INLINE
void _CFStreamLock(struct _CFStream
* stream
) {
96 __CFSpinLock(&_CFStreamGetAuxRecord(stream
)->streamLock
);
99 CF_INLINE
void _CFStreamUnlock(struct _CFStream
* stream
) {
100 __CFSpinUnlock(&_CFStreamGetAuxRecord(stream
)->streamLock
);
103 CF_INLINE CFRunLoopSourceRef
_CFStreamCopySource(struct _CFStream
* stream
) {
104 CFRunLoopSourceRef source
= NULL
;
107 _CFStreamLock(stream
);
110 source
= stream
->client
->rlSource
;
115 _CFStreamUnlock(stream
);
121 CF_INLINE
void _CFStreamSetSource(struct _CFStream
* stream
, CFRunLoopSourceRef source
, Boolean invalidateOldSource
) {
122 CFRunLoopSourceRef oldSource
= NULL
;
125 _CFStreamLock(stream
);
126 if (stream
->client
) {
127 oldSource
= stream
->client
->rlSource
;
128 if (oldSource
!= NULL
)
131 stream
->client
->rlSource
= source
;
135 _CFStreamUnlock(stream
);
139 // Lose our extra retain
140 CFRelease(oldSource
);
142 if (invalidateOldSource
)
143 CFRunLoopSourceInvalidate(oldSource
);
145 // And lose the one that held it in our stream as well
146 CFRelease(oldSource
);
150 CF_INLINE
const struct _CFStreamCallBacks
*_CFStreamGetCallBackPtr(struct _CFStream
*stream
) {
151 return stream
->callBacks
;
154 CF_INLINE
void _CFStreamSetStatusCode(struct _CFStream
*stream
, CFStreamStatus newStatus
) {
155 CFStreamStatus status
= __CFStreamGetStatus(stream
);
156 if (((status
!= kCFStreamStatusClosed
) && (status
!= kCFStreamStatusError
)) ||
157 ((status
== kCFStreamStatusClosed
) && (newStatus
== kCFStreamStatusError
)))
159 __CFBitfieldSetValue(stream
->flags
, MAX_STATUS_CODE_BIT
, MIN_STATUS_CODE_BIT
, newStatus
);
163 CF_INLINE
void _CFStreamScheduleEvent(struct _CFStream
*stream
, CFStreamEventType event
) {
164 if (stream
->client
&& (stream
->client
->when
& event
)) {
165 CFRunLoopSourceRef source
= _CFStreamCopySource(stream
);
167 stream
->client
->whatToSignal
|= event
;
169 CFRunLoopSourceSignal(source
);
171 _wakeUpRunLoop(stream
);
176 CF_INLINE
void _CFStreamSetStreamError(struct _CFStream
*stream
, CFStreamError
*err
) {
177 if (!stream
->error
) {
178 stream
->error
= (CFErrorRef
)CFAllocatorAllocate(CFGetAllocator(stream
), sizeof(CFStreamError
), 0);
180 memmove(stream
->error
, err
, sizeof(CFStreamError
));
183 static CFStringRef
__CFStreamCopyDescription(CFTypeRef cf
) {
184 struct _CFStream
*stream
= (struct _CFStream
*)cf
;
185 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
186 CFStringRef contextDescription
;
188 if (cb
->copyDescription
) {
189 if (cb
->version
== 0) {
190 contextDescription
= ((CFStringRef(*)(void *))cb
->copyDescription
)(_CFStreamGetInfoPointer(stream
));
192 contextDescription
= cb
->copyDescription(stream
, _CFStreamGetInfoPointer(stream
));
195 contextDescription
= CFStringCreateWithFormat(CFGetAllocator(stream
), NULL
, CFSTR("info = %p"), _CFStreamGetInfoPointer(stream
));
197 if (CFGetTypeID(cf
) == __kCFReadStreamTypeID
) {
198 desc
= CFStringCreateWithFormat(CFGetAllocator(stream
), NULL
, CFSTR("<CFReadStream %p>{%@}"), stream
, contextDescription
);
200 desc
= CFStringCreateWithFormat(CFGetAllocator(stream
), NULL
, CFSTR("<CFWriteStream %p>{%@}"), stream
, contextDescription
);
202 CFRelease(contextDescription
);
206 static void _CFStreamDetachSource(struct _CFStream
* stream
) {
207 if (stream
&& stream
->client
&& stream
->client
->rlSource
) {
208 if (!__CFBitIsSet(stream
->flags
, SHARED_SOURCE
)) {
209 _CFStreamSetSource(stream
, NULL
, TRUE
);
213 CFArrayRef runLoopAndSourceKey
;
214 CFMutableArrayRef list
;
218 __CFSpinLock(&sSourceLock
);
220 runLoopAndSourceKey
= (CFArrayRef
)CFDictionaryGetValue(sSharedSources
, stream
);
221 list
= (CFMutableArrayRef
)CFDictionaryGetValue(sSharedSources
, runLoopAndSourceKey
);
223 count
= CFArrayGetCount(list
);
224 i
= CFArrayGetFirstIndexOfValue(list
, CFRangeMake(0, count
), stream
);
225 if (i
!= kCFNotFound
) {
226 CFArrayRemoveValueAtIndex(list
, i
);
230 CFAssert(CFArrayGetFirstIndexOfValue(list
, CFRangeMake(0, CFArrayGetCount(list
)), stream
) == kCFNotFound
, __kCFLogAssertion
, "CFStreamClose: stream found twice in its shared source's list");
233 CFRunLoopSourceRef source
= _CFStreamCopySource(stream
);
235 CFRunLoopRemoveSource((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoopAndSourceKey
, 0), source
, (CFStringRef
)CFArrayGetValueAtIndex(runLoopAndSourceKey
, 1));
238 CFDictionaryRemoveValue(sSharedSources
, runLoopAndSourceKey
);
241 CFDictionaryRemoveValue(sSharedSources
, stream
);
243 _CFStreamSetSource(stream
, NULL
, count
== 0);
245 __CFBitClear(stream
->flags
, SHARED_SOURCE
);
247 __CFSpinUnlock(&sSourceLock
);
252 __private_extern__
void _CFStreamClose(struct _CFStream
*stream
) {
253 CFStreamStatus status
= _CFStreamGetStatus(stream
);
254 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
255 if (status
== kCFStreamStatusNotOpen
|| status
== kCFStreamStatusClosed
|| (status
== kCFStreamStatusError
&& __CFBitIsSet(stream
->flags
, HAVE_CLOSED
))) {
256 // Stream is not open from the client's perspective; do not callout and do not update our status to "closed"
259 __CFBitSet(stream
->flags
, HAVE_CLOSED
);
260 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
262 cb
->close(stream
, _CFStreamGetInfoPointer(stream
));
264 if (stream
->client
) {
265 _CFStreamDetachSource(stream
);
267 _CFStreamSetStatusCode(stream
, kCFStreamStatusClosed
);
268 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
271 //static int numStreamInstances = 0;
273 static void __CFStreamDeallocate(CFTypeRef cf
) {
274 struct _CFStream
*stream
= (struct _CFStream
*)cf
;
275 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
276 CFAllocatorRef alloc
= CFGetAllocator(stream
);
277 // numStreamInstances --;
280 _CFStreamClose(stream
);
282 if (stream
->client
) {
283 CFStreamClientContext
*cbContext
;
284 cbContext
= &(stream
->client
->cbContext
);
285 if (cbContext
->info
&& cbContext
->release
) {
286 cbContext
->release(cbContext
->info
);
288 _CFStreamDetachSource(stream
);
289 if (stream
->client
->runLoopsAndModes
) {
290 CFRelease(stream
->client
->runLoopsAndModes
);
293 CFAllocatorDeallocate(alloc
, stream
->client
);
294 stream
->client
= NULL
; // Just in case finalize, below, calls back in to us
297 if (cb
->version
== 0) {
298 ((void(*)(void *))cb
->finalize
)(_CFStreamGetInfoPointer(stream
));
300 cb
->finalize(stream
, _CFStreamGetInfoPointer(stream
));
304 if (cb
->version
< 2) {
305 CFAllocatorDeallocate(alloc
, stream
->error
);
307 CFRelease(stream
->error
);
310 if (!__CFBitIsSet(stream
->flags
, CONSTANT_CALLBACKS
)) {
311 CFAllocatorDeallocate(alloc
, (void *)stream
->callBacks
);
313 if (stream
->_reserved1
)
314 _CFStreamDestroyReserved(alloc
, stream
->_reserved1
);
317 static const CFRuntimeClass __CFReadStreamClass
= {
322 __CFStreamDeallocate
,
325 NULL
, // copyHumanDesc
326 __CFStreamCopyDescription
329 static const CFRuntimeClass __CFWriteStreamClass
= {
334 __CFStreamDeallocate
,
337 NULL
, // copyHumanDesc
338 __CFStreamCopyDescription
341 CONST_STRING_DECL(kCFStreamPropertySocketNativeHandle
, "kCFStreamPropertySocketNativeHandle")
342 CONST_STRING_DECL(kCFStreamPropertySocketRemoteHostName
, "kCFStreamPropertySocketRemoteHostName")
343 CONST_STRING_DECL(kCFStreamPropertySocketRemotePortNumber
, "kCFStreamPropertySocketRemotePortNumber")
344 CONST_STRING_DECL(kCFStreamPropertyDataWritten
, "kCFStreamPropertyDataWritten")
345 CONST_STRING_DECL(kCFStreamPropertyAppendToFile
, "kCFStreamPropertyAppendToFile")
347 __private_extern__
void __CFStreamInitialize(void) {
348 __kCFReadStreamTypeID
= _CFRuntimeRegisterClass(&__CFReadStreamClass
);
349 __kCFWriteStreamTypeID
= _CFRuntimeRegisterClass(&__CFWriteStreamClass
);
353 CF_EXPORT CFTypeID
CFReadStreamGetTypeID(void) {
354 return __kCFReadStreamTypeID
;
357 CF_EXPORT CFTypeID
CFWriteStreamGetTypeID(void) {
358 return __kCFWriteStreamTypeID
;
361 static struct _CFStream
*_CFStreamCreate(CFAllocatorRef allocator
, Boolean isReadStream
) {
362 struct _CFStream
*newStream
= (struct _CFStream
*)_CFRuntimeCreateInstance(allocator
, isReadStream
? __kCFReadStreamTypeID
: __kCFWriteStreamTypeID
, sizeof(struct _CFStream
) - sizeof(CFRuntimeBase
), NULL
);
364 // numStreamInstances ++;
365 newStream
->flags
= 0;
366 _CFStreamSetStatusCode(newStream
, kCFStreamStatusNotOpen
);
367 newStream
->error
= NULL
;
368 newStream
->client
= NULL
;
369 newStream
->info
= NULL
;
370 newStream
->callBacks
= NULL
;
372 newStream
->_reserved1
= _CFStreamCreateReserved(allocator
);
377 __private_extern__
struct _CFStream
*_CFStreamCreateWithConstantCallbacks(CFAllocatorRef alloc
, void *info
, const struct _CFStreamCallBacks
*cb
, Boolean isReading
) {
378 struct _CFStream
*newStream
;
379 if (cb
->version
!= 1) return NULL
;
380 newStream
= _CFStreamCreate(alloc
, isReading
);
382 __CFBitSet(newStream
->flags
, CONSTANT_CALLBACKS
);
383 newStream
->callBacks
= cb
;
385 newStream
->info
= cb
->create(newStream
, info
);
387 newStream
->info
= info
;
393 CF_EXPORT
void _CFStreamSetInfoPointer(struct _CFStream
*stream
, void *info
, const struct _CFStreamCallBacks
*cb
) {
394 if (info
!= stream
->info
) {
395 if (stream
->callBacks
->finalize
) {
396 stream
->callBacks
->finalize(stream
, stream
->info
);
399 stream
->info
= cb
->create(stream
, info
);
404 stream
->callBacks
= cb
;
408 CF_EXPORT CFReadStreamRef
CFReadStreamCreate(CFAllocatorRef alloc
, const CFReadStreamCallBacks
*callbacks
, void *info
) {
409 struct _CFStream
*newStream
= _CFStreamCreate(alloc
, TRUE
);
410 struct _CFStreamCallBacks
*cb
;
411 if (!newStream
) return NULL
;
412 cb
= (struct _CFStreamCallBacks
*)CFAllocatorAllocate(alloc
, sizeof(struct _CFStreamCallBacks
), 0);
414 CFRelease(newStream
);
417 if (callbacks
->version
== 0) {
418 CFReadStreamCallBacksV0
*cbV0
= (CFReadStreamCallBacksV0
*)callbacks
;
419 CFStreamClientContext
*ctxt
= (CFStreamClientContext
*)info
;
420 newStream
->info
= ctxt
->retain
? (void *)ctxt
->retain(ctxt
->info
) : ctxt
->info
;
422 cb
->create
= (void *(*)(struct _CFStream
*, void *))ctxt
->retain
;
423 cb
->finalize
= (void(*)(struct _CFStream
*, void *))ctxt
->release
;
424 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))ctxt
->copyDescription
;
425 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))cbV0
->open
;
426 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))cbV0
->openCompleted
;
427 cb
->read
= (CFIndex (*)(CFReadStreamRef
, UInt8
*, CFIndex
, CFErrorRef
*, Boolean
*, void *))cbV0
->read
;
428 cb
->getBuffer
= (const UInt8
*(*)(CFReadStreamRef
, CFIndex
, CFIndex
*, CFErrorRef
*, Boolean
*, void *))cbV0
->getBuffer
;
429 cb
->canRead
= (Boolean (*)(CFReadStreamRef
, CFErrorRef
*, void*))cbV0
->canRead
;
432 cb
->close
= (void (*)(struct _CFStream
*, void *))cbV0
->close
;
433 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))cbV0
->copyProperty
;
434 cb
->setProperty
= NULL
;
435 cb
->requestEvents
= NULL
;
436 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV0
->schedule
;
437 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV0
->unschedule
;
438 } else if (callbacks
->version
== 1) {
439 CFReadStreamCallBacksV1
*cbV1
= (CFReadStreamCallBacksV1
*)callbacks
;
440 newStream
->info
= cbV1
->create
? cbV1
->create((CFReadStreamRef
)newStream
, info
) : info
;
442 cb
->create
= (void *(*)(struct _CFStream
*, void *))cbV1
->create
;
443 cb
->finalize
= (void(*)(struct _CFStream
*, void *))cbV1
->finalize
;
444 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))cbV1
->copyDescription
;
445 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))cbV1
->open
;
446 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))cbV1
->openCompleted
;
447 cb
->read
= (CFIndex (*)(CFReadStreamRef
, UInt8
*, CFIndex
, CFErrorRef
*, Boolean
*, void *))cbV1
->read
;
448 cb
->getBuffer
= (const UInt8
*(*)(CFReadStreamRef
, CFIndex
, CFIndex
*, CFErrorRef
*, Boolean
*, void *))cbV1
->getBuffer
;
449 cb
->canRead
= (Boolean (*)(CFReadStreamRef
, CFErrorRef
*, void*))cbV1
->canRead
;
452 cb
->close
= (void (*)(struct _CFStream
*, void *))cbV1
->close
;
453 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))cbV1
->copyProperty
;
454 cb
->setProperty
= (Boolean(*)(struct _CFStream
*, CFStringRef
, CFTypeRef
, void *))cbV1
->setProperty
;
455 cb
->requestEvents
= (void(*)(struct _CFStream
*, CFOptionFlags
, void *))cbV1
->requestEvents
;
456 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV1
->schedule
;
457 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV1
->unschedule
;
459 newStream
->info
= callbacks
->create
? callbacks
->create((CFReadStreamRef
)newStream
, info
) : info
;
461 cb
->create
= (void *(*)(struct _CFStream
*, void *))callbacks
->create
;
462 cb
->finalize
= (void(*)(struct _CFStream
*, void *))callbacks
->finalize
;
463 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))callbacks
->copyDescription
;
464 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))callbacks
->open
;
465 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))callbacks
->openCompleted
;
466 cb
->read
= callbacks
->read
;
467 cb
->getBuffer
= callbacks
->getBuffer
;
468 cb
->canRead
= callbacks
->canRead
;
471 cb
->close
= (void (*)(struct _CFStream
*, void *))callbacks
->close
;
472 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))callbacks
->copyProperty
;
473 cb
->setProperty
= (Boolean(*)(struct _CFStream
*, CFStringRef
, CFTypeRef
, void *))callbacks
->setProperty
;
474 cb
->requestEvents
= (void(*)(struct _CFStream
*, CFOptionFlags
, void *))callbacks
->requestEvents
;
475 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))callbacks
->schedule
;
476 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))callbacks
->unschedule
;
479 newStream
->callBacks
= cb
;
480 return (CFReadStreamRef
)newStream
;
483 CF_EXPORT CFWriteStreamRef
CFWriteStreamCreate(CFAllocatorRef alloc
, const CFWriteStreamCallBacks
*callbacks
, void *info
) {
484 struct _CFStream
*newStream
= _CFStreamCreate(alloc
, FALSE
);
485 struct _CFStreamCallBacks
*cb
;
486 if (!newStream
) return NULL
;
487 cb
= (struct _CFStreamCallBacks
*)CFAllocatorAllocate(alloc
, sizeof(struct _CFStreamCallBacks
), 0);
489 CFRelease(newStream
);
492 if (callbacks
->version
== 0) {
493 CFWriteStreamCallBacksV0
*cbV0
= (CFWriteStreamCallBacksV0
*)callbacks
;
494 CFStreamClientContext
*ctxt
= (CFStreamClientContext
*)info
;
495 newStream
->info
= ctxt
->retain
? (void *)ctxt
->retain(ctxt
->info
) : ctxt
->info
;
497 cb
->create
= (void *(*)(struct _CFStream
*, void *))ctxt
->retain
;
498 cb
->finalize
= (void(*)(struct _CFStream
*, void *))ctxt
->release
;
499 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))ctxt
->copyDescription
;
500 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))cbV0
->open
;
501 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))cbV0
->openCompleted
;
503 cb
->getBuffer
= NULL
;
505 cb
->write
= (CFIndex(*)(CFWriteStreamRef stream
, const UInt8
*buffer
, CFIndex bufferLength
, CFErrorRef
*error
, void *info
))cbV0
->write
;
506 cb
->canWrite
= (Boolean(*)(CFWriteStreamRef stream
, CFErrorRef
*error
, void *info
))cbV0
->canWrite
;
507 cb
->close
= (void (*)(struct _CFStream
*, void *))cbV0
->close
;
508 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))cbV0
->copyProperty
;
509 cb
->setProperty
= NULL
;
510 cb
->requestEvents
= NULL
;
511 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV0
->schedule
;
512 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV0
->unschedule
;
513 } else if (callbacks
->version
== 1) {
514 CFWriteStreamCallBacksV1
*cbV1
= (CFWriteStreamCallBacksV1
*)callbacks
;
516 newStream
->info
= cbV1
->create
? cbV1
->create((CFWriteStreamRef
)newStream
, info
) : info
;
517 cb
->create
= (void *(*)(struct _CFStream
*, void *))cbV1
->create
;
518 cb
->finalize
= (void(*)(struct _CFStream
*, void *))cbV1
->finalize
;
519 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))cbV1
->copyDescription
;
520 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))cbV1
->open
;
521 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))cbV1
->openCompleted
;
523 cb
->getBuffer
= NULL
;
525 cb
->write
= (CFIndex(*)(CFWriteStreamRef stream
, const UInt8
*buffer
, CFIndex bufferLength
, CFErrorRef
*error
, void *info
))cbV1
->write
;
526 cb
->canWrite
= (Boolean(*)(CFWriteStreamRef stream
, CFErrorRef
*error
, void *info
))cbV1
->canWrite
;
527 cb
->close
= (void (*)(struct _CFStream
*, void *))cbV1
->close
;
528 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))cbV1
->copyProperty
;
529 cb
->setProperty
= (Boolean (*)(struct _CFStream
*, CFStringRef
, CFTypeRef
, void *))cbV1
->setProperty
;
530 cb
->requestEvents
= (void(*)(struct _CFStream
*, CFOptionFlags
, void *))cbV1
->requestEvents
;
531 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV1
->schedule
;
532 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV1
->unschedule
;
534 cb
->version
= callbacks
->version
;
535 newStream
->info
= callbacks
->create
? callbacks
->create((CFWriteStreamRef
)newStream
, info
) : info
;
536 cb
->create
= (void *(*)(struct _CFStream
*, void *))callbacks
->create
;
537 cb
->finalize
= (void(*)(struct _CFStream
*, void *))callbacks
->finalize
;
538 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))callbacks
->copyDescription
;
539 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))callbacks
->open
;
540 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))callbacks
->openCompleted
;
542 cb
->getBuffer
= NULL
;
544 cb
->write
= callbacks
->write
;
545 cb
->canWrite
= callbacks
->canWrite
;
546 cb
->close
= (void (*)(struct _CFStream
*, void *))callbacks
->close
;
547 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))callbacks
->copyProperty
;
548 cb
->setProperty
= (Boolean (*)(struct _CFStream
*, CFStringRef
, CFTypeRef
, void *))callbacks
->setProperty
;
549 cb
->requestEvents
= (void(*)(struct _CFStream
*, CFOptionFlags
, void *))callbacks
->requestEvents
;
550 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))callbacks
->schedule
;
551 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))callbacks
->unschedule
;
553 newStream
->callBacks
= cb
;
554 return (CFWriteStreamRef
)newStream
;
557 static void _signalEventSync(struct _CFStream
* stream
, CFOptionFlags whatToSignal
)
559 CFOptionFlags eventMask
;
561 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
564 void (*release
) (void*) = NULL
;
566 if (stream
->client
->cbContext
.retain
== NULL
)
567 info
= stream
->client
->cbContext
.info
;
569 info
= stream
->client
->cbContext
.retain(stream
->client
->cbContext
.info
);
570 release
= stream
->client
->cbContext
.release
;
573 for (eventMask
= 1; eventMask
<= whatToSignal
; eventMask
= eventMask
<< 1) {
574 if ((eventMask
& whatToSignal
) && (stream
->client
->when
& eventMask
)) {
575 stream
->client
->cb(stream
, eventMask
, info
);
577 /* What happens if the callback sets the client to NULL? We're in a loop here... Hmm. */
578 /* After writing that comment, I see: <rdar://problem/6793636> CFReadStreamSetClient(..., NULL) unsafely releases info pointer immediately */
579 /* Of note, when the stream callbacks are set to to NULL, we're re-initalized so as not to receive more events, so we
580 * should break pout of this loop */
587 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
590 static void _cfstream_solo_signalEventSync(void* info
)
592 CFTypeID typeID
= CFGetTypeID((CFTypeRef
) info
);
594 if (typeID
!= CFReadStreamGetTypeID() && typeID
!= CFWriteStreamGetTypeID()) {
595 CFLog(__kCFLogAssertion
, CFSTR("Expected an read or write stream for %p"), info
);
600 struct _CFStream
* stream
= (struct _CFStream
*) info
;
601 CFOptionFlags whatToSignal
= stream
->client
->whatToSignal
;
602 stream
->client
->whatToSignal
= 0;
604 /* Since the array version holds a retain, we do it here as well, as opposed to taking a second retain in the client callback */
606 _signalEventSync(stream
, whatToSignal
);
611 static void _cfstream_shared_signalEventSync(void* info
)
613 CFTypeID typeID
= CFGetTypeID((CFTypeRef
) info
);
615 if (typeID
!= CFArrayGetTypeID()) {
616 CFLog(__kCFLogAssertion
, CFSTR("Expected an array for %p"), info
);
621 CFMutableArrayRef list
= (CFMutableArrayRef
) info
;
623 CFOptionFlags whatToSignal
= 0;
624 struct _CFStream
* stream
= NULL
;
626 __CFSpinLock(&sSourceLock
);
628 /* Looks like, we grab the first stream that wants an event... */
629 /* Note that I grab an extra retain when I pull out the stream here... */
630 c
= CFArrayGetCount(list
);
631 for (i
= 0; i
< c
; i
++) {
632 struct _CFStream
* s
= (struct _CFStream
*)CFArrayGetValueAtIndex(list
, i
);
634 if (s
->client
->whatToSignal
) {
637 whatToSignal
= stream
->client
->whatToSignal
;
638 s
->client
->whatToSignal
= 0;
643 /* And then we also signal any other streams in this array so that we get them next go? */
645 struct _CFStream
* s
= (struct _CFStream
*)CFArrayGetValueAtIndex(list
, i
);
646 if (s
->client
->whatToSignal
) {
647 CFRunLoopSourceRef source
= _CFStreamCopySource(s
);
649 CFRunLoopSourceSignal(source
);
656 __CFSpinUnlock(&sSourceLock
);
658 /* We're sitting here now, possibly with a stream that needs to be processed by the common routine */
660 _signalEventSync(stream
, whatToSignal
);
662 /* Lose our extra retain */
668 // Largely cribbed from CFSocket.c; find a run loop where our source is scheduled and wake it up. We skip the runloop cycling, so we
669 // are likely to signal the same run loop over and over again. Don't know if we should worry about that.
670 static void _wakeUpRunLoop(struct _CFStream
*stream
) {
671 CFRunLoopRef rl
= NULL
;
674 if (!stream
->client
|| !stream
->client
->runLoopsAndModes
) return;
675 rlArray
= stream
->client
->runLoopsAndModes
;
676 cnt
= CFArrayGetCount(rlArray
);
677 if (cnt
== 0) return;
679 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, 0);
681 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, 0);
682 for (idx
= 2; NULL
!= rl
&& idx
< cnt
; idx
+=2) {
683 CFRunLoopRef value
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, idx
);
684 if (value
!= rl
) rl
= NULL
;
686 if (NULL
== rl
) { /* more than one different rl, so we must pick one */
687 for (idx
= 0; idx
< cnt
; idx
+=2) {
688 CFRunLoopRef value
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, idx
);
689 CFStringRef currentMode
= CFRunLoopCopyCurrentMode(value
);
690 if (NULL
!= currentMode
&& CFEqual(currentMode
, CFArrayGetValueAtIndex(rlArray
, idx
+1)) && CFRunLoopIsWaiting(value
)) {
691 CFRelease(currentMode
);
695 if (NULL
!= currentMode
) CFRelease(currentMode
);
697 if (NULL
== rl
) { /* didn't choose one above, so choose first */
698 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, 0);
702 if (NULL
!= rl
&& CFRunLoopIsWaiting(rl
)) CFRunLoopWakeUp(rl
);
705 __private_extern__
void _CFStreamSignalEvent(struct _CFStream
*stream
, CFStreamEventType event
, CFErrorRef error
, Boolean synchronousAllowed
) {
706 // Update our internal status; we must use the primitive __CFStreamGetStatus(), because CFStreamGetStatus() calls us, and we can end up in an infinite loop.
707 CFStreamStatus status
= __CFStreamGetStatus(stream
);
709 // Sanity check the event
710 if (status
== kCFStreamStatusNotOpen
) {
711 // No events allowed; this is almost certainly a bug in the stream's implementation
712 CFLog(__kCFLogAssertion
, CFSTR("Stream %p is sending an event before being opened"), stream
);
714 } else if (status
== kCFStreamStatusClosed
|| status
== kCFStreamStatusError
) {
715 // no further events are allowed
717 } else if (status
== kCFStreamStatusAtEnd
) {
718 // Only error events are allowed
719 event
&= kCFStreamEventErrorOccurred
;
720 } else if (status
!= kCFStreamStatusOpening
) {
721 // cannot send open completed; that happened already
722 event
&= ~kCFStreamEventOpenCompleted
;
725 // Change status if appropriate
726 if (event
& kCFStreamEventOpenCompleted
&& status
== kCFStreamStatusOpening
) {
727 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
729 if (event
& kCFStreamEventEndEncountered
&& status
< kCFStreamStatusAtEnd
) {
730 _CFStreamSetStatusCode(stream
, kCFStreamStatusAtEnd
);
732 if (event
& kCFStreamEventErrorOccurred
) {
733 if (_CFStreamGetCallBackPtr(stream
)->version
< 2) {
734 _CFStreamSetStreamError(stream
, (CFStreamError
*)error
);
736 CFAssert(error
, __kCFLogAssertion
, "CFStream: kCFStreamEventErrorOccurred signalled, but error is NULL!");
738 if (stream
->error
) CFRelease(stream
->error
);
739 stream
->error
= error
;
741 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
744 // Now signal any pertinent event
745 if (stream
->client
&& (stream
->client
->when
& event
) != 0) {
746 CFRunLoopSourceRef source
= _CFStreamCopySource(stream
);
749 Boolean signalNow
= FALSE
;
751 stream
->client
->whatToSignal
|= event
;
753 if (synchronousAllowed
&& !__CFBitIsSet(stream
->flags
, CALLING_CLIENT
)) {
755 CFRunLoopRef rl
= CFRunLoopGetCurrent();
756 CFStringRef mode
= CFRunLoopCopyCurrentMode(rl
);
759 if (CFRunLoopContainsSource(rl
, source
, mode
))
767 // Can call out safely right now
768 _cfstream_solo_signalEventSync(stream
);
770 // Schedule for later delivery
772 CFRunLoopSourceSignal(source
);
774 _wakeUpRunLoop(stream
);
782 __private_extern__ CFStreamStatus
_CFStreamGetStatus(struct _CFStream
*stream
) {
783 CFStreamStatus status
= __CFStreamGetStatus(stream
);
784 // 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.
785 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
786 if (status
== kCFStreamStatusOpening
) {
787 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
788 if (cb
->openCompleted
) {
790 if (cb
->version
< 2) {
791 CFStreamError err
= {0, 0};
792 isComplete
= ((_CFStreamCBOpenCompletedV1
)(cb
->openCompleted
))(stream
, &err
, _CFStreamGetInfoPointer(stream
));
793 if (err
.error
!= 0) _CFStreamSetStreamError(stream
, &err
);
795 isComplete
= cb
->openCompleted(stream
, &(stream
->error
), _CFStreamGetInfoPointer(stream
));
798 if (!stream
->error
) {
799 status
= kCFStreamStatusOpen
;
801 status
= kCFStreamStatusError
;
803 _CFStreamSetStatusCode(stream
, status
);
804 if (status
== kCFStreamStatusOpen
) {
805 _CFStreamScheduleEvent(stream
, kCFStreamEventOpenCompleted
);
807 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
812 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
816 CF_EXPORT CFStreamStatus
CFReadStreamGetStatus(CFReadStreamRef stream
) {
817 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID
, CFStreamStatus
, stream
, "streamStatus");
818 return _CFStreamGetStatus((struct _CFStream
*)stream
);
821 CF_EXPORT CFStreamStatus
CFWriteStreamGetStatus(CFWriteStreamRef stream
) {
822 CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID
, CFStreamStatus
, stream
, "streamStatus");
823 return _CFStreamGetStatus((struct _CFStream
*)stream
);
826 static CFStreamError
_CFStreamGetStreamError(struct _CFStream
*stream
) {
827 CFStreamError result
;
828 if (!stream
->error
) {
831 } else if (_CFStreamGetCallBackPtr(stream
)->version
< 2) {
832 CFStreamError
*streamError
= (CFStreamError
*)(stream
->error
);
833 result
.error
= streamError
->error
;
834 result
.domain
= streamError
->domain
;
836 result
= _CFStreamErrorFromError(stream
->error
);
841 CF_EXPORT CFStreamError
CFReadStreamGetError(CFReadStreamRef stream
) {
842 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID
, CFStreamError
, stream
, "_cfStreamError");
843 return _CFStreamGetStreamError((struct _CFStream
*)stream
);
846 CF_EXPORT CFStreamError
CFWriteStreamGetError(CFWriteStreamRef stream
) {
847 CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID
, CFStreamError
, stream
, "_cfStreamError");
848 return _CFStreamGetStreamError((struct _CFStream
*)stream
);
851 static CFErrorRef
_CFStreamCopyError(struct _CFStream
*stream
) {
852 if (!stream
->error
) {
854 } else if (_CFStreamGetCallBackPtr(stream
)->version
< 2) {
855 return _CFErrorFromStreamError(CFGetAllocator(stream
), (CFStreamError
*)(stream
->error
));
857 CFRetain(stream
->error
);
858 return stream
->error
;
862 CF_EXPORT CFErrorRef
CFReadStreamCopyError(CFReadStreamRef stream
) {
863 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID
, CFErrorRef
, stream
, "streamError");
864 return _CFStreamCopyError((struct _CFStream
*)stream
);
867 CF_EXPORT CFErrorRef
CFWriteStreamCopyError(CFWriteStreamRef stream
) {
868 return _CFStreamCopyError((struct _CFStream
*)stream
);
869 CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID
, CFErrorRef
, stream
, "streamError");
872 __private_extern__ Boolean
_CFStreamOpen(struct _CFStream
*stream
) {
873 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
874 Boolean success
, openComplete
;
875 if (_CFStreamGetStatus(stream
) != kCFStreamStatusNotOpen
) {
878 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
879 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpening
);
881 if (cb
->version
< 2) {
882 CFStreamError err
= {0, 0};
883 success
= ((_CFStreamCBOpenV1
)(cb
->open
))(stream
, &err
, &openComplete
, _CFStreamGetInfoPointer(stream
));
884 if (err
.error
!= 0) _CFStreamSetStreamError(stream
, &err
);
886 success
= cb
->open(stream
, &(stream
->error
), &openComplete
, _CFStreamGetInfoPointer(stream
));
894 // 2957690 - Guard against the possibility that the stream has already signalled itself in to a later state (like AtEnd)
895 if (__CFStreamGetStatus(stream
) == kCFStreamStatusOpening
) {
896 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
898 _CFStreamScheduleEvent(stream
, kCFStreamEventOpenCompleted
);
900 #if DEPLOYMENT_TARGET_WINDOWS
901 _CFStreamClose(stream
);
903 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
904 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
907 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
911 CF_EXPORT Boolean
CFReadStreamOpen(CFReadStreamRef stream
) {
912 if(CF_IS_OBJC(__kCFReadStreamTypeID
, stream
)) {
913 CF_OBJC_VOIDCALL0(stream
, "open");
916 return _CFStreamOpen((struct _CFStream
*)stream
);
919 CF_EXPORT Boolean
CFWriteStreamOpen(CFWriteStreamRef stream
) {
920 if(CF_IS_OBJC(__kCFWriteStreamTypeID
, stream
)) {
921 CF_OBJC_VOIDCALL0(stream
, "open");
924 return _CFStreamOpen((struct _CFStream
*)stream
);
927 CF_EXPORT
void CFReadStreamClose(CFReadStreamRef stream
) {
928 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID
, void, stream
, "close");
929 _CFStreamClose((struct _CFStream
*)stream
);
932 CF_EXPORT
void CFWriteStreamClose(CFWriteStreamRef stream
) {
933 CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID
, void, stream
, "close");
934 _CFStreamClose((struct _CFStream
*)stream
);
937 CF_EXPORT Boolean
CFReadStreamHasBytesAvailable(CFReadStreamRef readStream
) {
938 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID
, Boolean
, readStream
, "hasBytesAvailable");
939 struct _CFStream
*stream
= (struct _CFStream
*)readStream
;
940 CFStreamStatus status
= _CFStreamGetStatus(stream
);
941 const struct _CFStreamCallBacks
*cb
;
942 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusReading
) {
945 cb
= _CFStreamGetCallBackPtr(stream
);
946 if (cb
->canRead
== NULL
) {
947 return TRUE
; // No way to know without trying....
950 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
951 if (cb
->version
< 2) {
952 result
= ((_CFStreamCBCanReadV1
)(cb
->canRead
))((CFReadStreamRef
)stream
, _CFStreamGetInfoPointer(stream
));
954 result
= cb
->canRead((CFReadStreamRef
)stream
, &(stream
->error
), _CFStreamGetInfoPointer(stream
));
956 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
957 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
960 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
965 static void waitForOpen(struct _CFStream
*stream
);
966 CFIndex
CFReadStreamRead(CFReadStreamRef readStream
, UInt8
*buffer
, CFIndex bufferLength
) {
967 CF_OBJC_FUNCDISPATCH2(__kCFReadStreamTypeID
, CFIndex
, readStream
, "read:maxLength:", buffer
, bufferLength
);
968 struct _CFStream
*stream
= (struct _CFStream
*)readStream
;
969 CFStreamStatus status
= _CFStreamGetStatus(stream
);
970 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
971 if (status
== kCFStreamStatusOpening
) {
972 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
974 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
975 status
= _CFStreamGetStatus(stream
);
978 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusReading
&& status
!= kCFStreamStatusAtEnd
) {
980 } else if (status
== kCFStreamStatusAtEnd
) {
985 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
986 if (stream
->client
) {
987 stream
->client
->whatToSignal
&= ~kCFStreamEventHasBytesAvailable
;
989 _CFStreamSetStatusCode(stream
, kCFStreamStatusReading
);
990 if (cb
->version
< 2) {
991 CFStreamError err
= {0, 0};
992 bytesRead
= ((_CFStreamCBReadV1
)(cb
->read
))((CFReadStreamRef
)stream
, buffer
, bufferLength
, &err
, &atEOF
, _CFStreamGetInfoPointer(stream
));
993 if (err
.error
!= 0) _CFStreamSetStreamError(stream
, &err
);
995 bytesRead
= cb
->read((CFReadStreamRef
)stream
, buffer
, bufferLength
, &(stream
->error
), &atEOF
, _CFStreamGetInfoPointer(stream
));
999 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
1000 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
1002 _CFStreamSetStatusCode(stream
, kCFStreamStatusAtEnd
);
1003 _CFStreamScheduleEvent(stream
, kCFStreamEventEndEncountered
);
1005 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
1007 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1012 CF_EXPORT
const UInt8
*CFReadStreamGetBuffer(CFReadStreamRef readStream
, CFIndex maxBytesToRead
, CFIndex
*numBytesRead
) {
1013 if (CF_IS_OBJC(__kCFReadStreamTypeID
, readStream
)) {
1014 uint8_t *bufPtr
= NULL
;
1016 CF_OBJC_CALL2(Boolean
, gotBytes
, readStream
, "getBuffer:length:", &bufPtr
, numBytesRead
);
1018 return (const UInt8
*)bufPtr
;
1023 struct _CFStream
*stream
= (struct _CFStream
*)readStream
;
1024 CFStreamStatus status
= _CFStreamGetStatus(stream
);
1025 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1026 const UInt8
*buffer
;
1027 if (status
== kCFStreamStatusOpening
) {
1028 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1029 waitForOpen(stream
);
1030 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1031 status
= _CFStreamGetStatus(stream
);
1033 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusReading
&& status
!= kCFStreamStatusAtEnd
) {
1036 } else if (status
== kCFStreamStatusAtEnd
|| cb
->getBuffer
== NULL
) {
1041 Boolean hadBytes
= stream
->client
&& (stream
->client
->whatToSignal
& kCFStreamEventHasBytesAvailable
);
1042 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1044 stream
->client
->whatToSignal
&= ~kCFStreamEventHasBytesAvailable
;
1046 _CFStreamSetStatusCode(stream
, kCFStreamStatusReading
);
1047 if (cb
->version
< 2) {
1048 CFStreamError err
= {0, 0};
1049 buffer
= ((_CFStreamCBGetBufferV1
)(cb
->getBuffer
))((CFReadStreamRef
)stream
, maxBytesToRead
, numBytesRead
, &err
, &atEOF
, _CFStreamGetInfoPointer(stream
));
1050 if (err
.error
!= 0) _CFStreamSetStreamError(stream
, &err
);
1052 buffer
= cb
->getBuffer((CFReadStreamRef
)stream
, maxBytesToRead
, numBytesRead
, &(stream
->error
), &atEOF
, _CFStreamGetInfoPointer(stream
));
1054 if (stream
->error
) {
1056 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
1058 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
1060 _CFStreamSetStatusCode(stream
, kCFStreamStatusAtEnd
);
1061 _CFStreamScheduleEvent(stream
, kCFStreamEventEndEncountered
);
1063 if (!buffer
&& hadBytes
) {
1064 stream
->client
->whatToSignal
|= kCFStreamEventHasBytesAvailable
;
1066 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
1068 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1073 CF_EXPORT Boolean
CFWriteStreamCanAcceptBytes(CFWriteStreamRef writeStream
) {
1074 CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID
, Boolean
, writeStream
, "hasSpaceAvailable");
1075 struct _CFStream
*stream
= (struct _CFStream
*)writeStream
;
1076 CFStreamStatus status
= _CFStreamGetStatus(stream
);
1077 const struct _CFStreamCallBacks
*cb
;
1078 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusWriting
) {
1081 cb
= _CFStreamGetCallBackPtr(stream
);
1082 if (cb
->canWrite
== NULL
) {
1083 return TRUE
; // No way to know without trying....
1086 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1087 if (cb
->version
< 2) {
1088 result
= ((_CFStreamCBCanWriteV1
)(cb
->canWrite
))((CFWriteStreamRef
)stream
, _CFStreamGetInfoPointer(stream
));
1090 result
= cb
->canWrite((CFWriteStreamRef
)stream
, &(stream
->error
), _CFStreamGetInfoPointer(stream
));
1091 if (stream
->error
) {
1092 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
1093 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
1096 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1101 CF_EXPORT CFIndex
CFWriteStreamWrite(CFWriteStreamRef writeStream
, const UInt8
*buffer
, CFIndex bufferLength
) {
1102 CF_OBJC_FUNCDISPATCH2(__kCFWriteStreamTypeID
, CFIndex
, writeStream
, "write:maxLength:", buffer
, bufferLength
);
1103 struct _CFStream
*stream
= (struct _CFStream
*)writeStream
;
1104 CFStreamStatus status
= _CFStreamGetStatus(stream
);
1105 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1106 if (status
== kCFStreamStatusOpening
) {
1107 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1108 waitForOpen(stream
);
1109 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1110 status
= _CFStreamGetStatus(stream
);
1112 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusWriting
) {
1116 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1117 _CFStreamSetStatusCode(stream
, kCFStreamStatusWriting
);
1118 if (stream
->client
) {
1119 stream
->client
->whatToSignal
&= ~kCFStreamEventCanAcceptBytes
;
1121 if (cb
->version
< 2) {
1122 CFStreamError err
= {0, 0};
1123 result
= ((_CFStreamCBWriteV1
)(cb
->write
))((CFWriteStreamRef
)stream
, buffer
, bufferLength
, &err
, _CFStreamGetInfoPointer(stream
));
1124 if (err
.error
) _CFStreamSetStreamError(stream
, &err
);
1126 result
= cb
->write((CFWriteStreamRef
)stream
, buffer
, bufferLength
, &(stream
->error
), _CFStreamGetInfoPointer(stream
));
1128 if (stream
->error
) {
1129 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
1130 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
1131 } else if (result
== 0) {
1132 _CFStreamSetStatusCode(stream
, kCFStreamStatusAtEnd
);
1133 _CFStreamScheduleEvent(stream
, kCFStreamEventEndEncountered
);
1135 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
1137 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1142 __private_extern__ CFTypeRef
_CFStreamCopyProperty(struct _CFStream
*stream
, CFStringRef propertyName
) {
1143 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1144 if (cb
->copyProperty
== NULL
) {
1148 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1149 result
= cb
->copyProperty(stream
, propertyName
, _CFStreamGetInfoPointer(stream
));
1150 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1155 CF_EXPORT CFTypeRef
CFReadStreamCopyProperty(CFReadStreamRef stream
, CFStringRef propertyName
) {
1156 CF_OBJC_FUNCDISPATCH1(__kCFReadStreamTypeID
, CFTypeRef
, stream
, "propertyForKey:", propertyName
);
1157 return _CFStreamCopyProperty((struct _CFStream
*)stream
, propertyName
);
1160 CF_EXPORT CFTypeRef
CFWriteStreamCopyProperty(CFWriteStreamRef stream
, CFStringRef propertyName
) {
1161 CF_OBJC_FUNCDISPATCH1(__kCFWriteStreamTypeID
, CFTypeRef
, stream
, "propertyForKey:", propertyName
);
1162 return _CFStreamCopyProperty((struct _CFStream
*)stream
, propertyName
);
1165 __private_extern__ Boolean
_CFStreamSetProperty(struct _CFStream
*stream
, CFStringRef prop
, CFTypeRef val
) {
1166 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1167 if (cb
->setProperty
== NULL
) {
1171 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1172 result
= cb
->setProperty(stream
, prop
, val
, _CFStreamGetInfoPointer(stream
));
1173 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1179 Boolean
CFReadStreamSetProperty(CFReadStreamRef stream
, CFStringRef propertyName
, CFTypeRef propertyValue
) {
1180 CF_OBJC_FUNCDISPATCH2(__kCFReadStreamTypeID
, Boolean
, stream
, "setProperty:forKey:", propertyValue
, propertyName
);
1181 return _CFStreamSetProperty((struct _CFStream
*)stream
, propertyName
, propertyValue
);
1185 Boolean
CFWriteStreamSetProperty(CFWriteStreamRef stream
, CFStringRef propertyName
, CFTypeRef propertyValue
) {
1186 CF_OBJC_FUNCDISPATCH2(__kCFWriteStreamTypeID
, Boolean
, stream
, "setProperty:forKey:", propertyValue
, propertyName
);
1187 return _CFStreamSetProperty((struct _CFStream
*)stream
, propertyName
, propertyValue
);
1190 static void _initializeClient(struct _CFStream
*stream
) {
1191 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1192 if (!cb
->schedule
) return; // Do we wish to allow this?
1193 stream
->client
= (struct _CFStreamClient
*)CFAllocatorAllocate(CFGetAllocator(stream
), sizeof(struct _CFStreamClient
), 0);
1194 memset(stream
->client
, 0, sizeof(struct _CFStreamClient
));
1197 /* If we add a setClient callback to the concrete stream callbacks, we must set/clear CALLING_CLIENT around it */
1198 __private_extern__ Boolean
_CFStreamSetClient(struct _CFStream
*stream
, CFOptionFlags streamEvents
, void (*clientCB
)(struct _CFStream
*, CFStreamEventType
, void *), CFStreamClientContext
*clientCallBackContext
) {
1200 Boolean removingClient
= (streamEvents
== kCFStreamEventNone
|| clientCB
== NULL
|| clientCallBackContext
== NULL
);
1202 if (removingClient
) {
1204 streamEvents
= kCFStreamEventNone
;
1205 clientCallBackContext
= NULL
;
1207 if (!stream
->client
) {
1208 if (removingClient
) {
1209 // We have no client now, and we've been asked to add none???
1212 _initializeClient(stream
);
1213 if (!stream
->client
) {
1214 // Asynch not supported
1218 if (stream
->client
->cb
&& stream
->client
->cbContext
.release
) {
1219 stream
->client
->cbContext
.release(stream
->client
->cbContext
.info
);
1221 stream
->client
->cb
= clientCB
;
1222 if (clientCallBackContext
) {
1223 stream
->client
->cbContext
.version
= clientCallBackContext
->version
;
1224 stream
->client
->cbContext
.retain
= clientCallBackContext
->retain
;
1225 stream
->client
->cbContext
.release
= clientCallBackContext
->release
;
1226 stream
->client
->cbContext
.copyDescription
= clientCallBackContext
->copyDescription
;
1227 stream
->client
->cbContext
.info
= (clientCallBackContext
->retain
&& clientCallBackContext
->info
) ? clientCallBackContext
->retain(clientCallBackContext
->info
) : clientCallBackContext
->info
;
1229 stream
->client
->cbContext
.retain
= NULL
;
1230 stream
->client
->cbContext
.release
= NULL
;
1231 stream
->client
->cbContext
.copyDescription
= NULL
;
1232 stream
->client
->cbContext
.info
= NULL
;
1234 if (stream
->client
->when
!= streamEvents
) {
1235 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1236 stream
->client
->when
= streamEvents
;
1237 if (cb
->requestEvents
) {
1238 cb
->requestEvents(stream
, streamEvents
, _CFStreamGetInfoPointer(stream
));
1244 CF_EXPORT Boolean
CFReadStreamSetClient(CFReadStreamRef readStream
, CFOptionFlags streamEvents
, CFReadStreamClientCallBack clientCB
, CFStreamClientContext
*clientContext
) {
1245 CF_OBJC_FUNCDISPATCH3(__kCFReadStreamTypeID
, Boolean
, readStream
, "_setCFClientFlags:callback:context:", streamEvents
, clientCB
, clientContext
);
1246 streamEvents
&= ~kCFStreamEventCanAcceptBytes
;
1247 return _CFStreamSetClient((struct _CFStream
*)readStream
, streamEvents
, (void (*)(struct _CFStream
*, CFStreamEventType
, void *))clientCB
, clientContext
);
1250 CF_EXPORT Boolean
CFWriteStreamSetClient(CFWriteStreamRef writeStream
, CFOptionFlags streamEvents
, CFWriteStreamClientCallBack clientCB
, CFStreamClientContext
*clientContext
) {
1251 CF_OBJC_FUNCDISPATCH3(__kCFWriteStreamTypeID
, Boolean
, writeStream
, "_setCFClientFlags:callback:context:", streamEvents
, clientCB
, clientContext
);
1252 streamEvents
&= ~kCFStreamEventHasBytesAvailable
;
1253 return _CFStreamSetClient((struct _CFStream
*)writeStream
, streamEvents
, (void (*)(struct _CFStream
*, CFStreamEventType
, void *))clientCB
, clientContext
);
1256 CF_INLINE
void *_CFStreamGetClient(struct _CFStream
*stream
) {
1257 if (stream
->client
) return stream
->client
->cbContext
.info
;
1261 CF_EXPORT
void *_CFReadStreamGetClient(CFReadStreamRef readStream
) {
1262 return _CFStreamGetClient((struct _CFStream
*)readStream
);
1265 CF_EXPORT
void *_CFWriteStreamGetClient(CFWriteStreamRef writeStream
) {
1266 return _CFStreamGetClient((struct _CFStream
*)writeStream
);
1270 __private_extern__
void _CFStreamScheduleWithRunLoop(struct _CFStream
*stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1271 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1273 if (! stream
->client
) {
1274 _initializeClient(stream
);
1275 if (!stream
->client
) return; // we don't support asynch.
1278 if (! stream
->client
->rlSource
) {
1279 /* No source, so we join the shared source group */
1280 CFTypeRef a
[] = { runLoop
, runLoopMode
};
1282 CFArrayRef runLoopAndSourceKey
= CFArrayCreate(kCFAllocatorSystemDefault
, a
, sizeof(a
) / sizeof(a
[0]), &kCFTypeArrayCallBacks
);
1284 __CFSpinLock(&sSourceLock
);
1286 if (!sSharedSources
)
1287 sSharedSources
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1289 CFMutableArrayRef listOfStreamsSharingASource
= (CFMutableArrayRef
)CFDictionaryGetValue(sSharedSources
, runLoopAndSourceKey
);
1290 if (listOfStreamsSharingASource
) {
1291 struct _CFStream
* aStream
= (struct _CFStream
*) CFArrayGetValueAtIndex(listOfStreamsSharingASource
, 0);
1292 CFRunLoopSourceRef source
= _CFStreamCopySource(aStream
);
1294 _CFStreamSetSource(stream
, source
, FALSE
);
1297 CFRetain(listOfStreamsSharingASource
);
1300 CFRunLoopSourceContext ctxt
= {
1305 (CFStringRef(*)(const void *))CFCopyDescription
,
1310 (void(*)(void *))_cfstream_shared_signalEventSync
1313 listOfStreamsSharingASource
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
1314 CFDictionaryAddValue(sSharedSources
, runLoopAndSourceKey
, listOfStreamsSharingASource
);
1316 ctxt
.info
= listOfStreamsSharingASource
;
1318 CFRunLoopSourceRef source
= CFRunLoopSourceCreate(kCFAllocatorSystemDefault
, 0, &ctxt
);
1319 _CFStreamSetSource(stream
, source
, FALSE
);
1320 CFRunLoopAddSource(runLoop
, source
, runLoopMode
);
1324 CFArrayAppendValue(listOfStreamsSharingASource
, stream
);
1325 CFDictionaryAddValue(sSharedSources
, stream
, runLoopAndSourceKey
);
1327 CFRelease(runLoopAndSourceKey
);
1328 CFRelease(listOfStreamsSharingASource
);
1330 __CFBitSet(stream
->flags
, SHARED_SOURCE
);
1332 __CFSpinUnlock(&sSourceLock
);
1334 else if (__CFBitIsSet(stream
->flags
, SHARED_SOURCE
)) {
1335 /* We were sharing, but now we'll get our own source */
1337 CFArrayRef runLoopAndSourceKey
;
1338 CFMutableArrayRef listOfStreamsSharingASource
;
1341 CFAllocatorRef alloc
= CFGetAllocator(stream
);
1342 CFRunLoopSourceContext ctxt
= {
1345 NULL
, // Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop
1346 NULL
, // Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop
1347 (CFStringRef(*)(const void *))CFCopyDescription
,
1352 (void(*)(void *))_cfstream_solo_signalEventSync
1355 __CFSpinLock(&sSourceLock
);
1357 runLoopAndSourceKey
= (CFArrayRef
)CFRetain((CFTypeRef
)CFDictionaryGetValue(sSharedSources
, stream
));
1358 listOfStreamsSharingASource
= (CFMutableArrayRef
)CFDictionaryGetValue(sSharedSources
, runLoopAndSourceKey
);
1360 count
= CFArrayGetCount(listOfStreamsSharingASource
);
1361 i
= CFArrayGetFirstIndexOfValue(listOfStreamsSharingASource
, CFRangeMake(0, count
), stream
);
1362 if (i
!= kCFNotFound
) {
1363 CFArrayRemoveValueAtIndex(listOfStreamsSharingASource
, i
);
1368 CFRunLoopSourceRef source
= _CFStreamCopySource(stream
);
1370 CFRunLoopRemoveSource((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoopAndSourceKey
, 0), source
, (CFStringRef
)CFArrayGetValueAtIndex(runLoopAndSourceKey
, 1));
1373 CFDictionaryRemoveValue(sSharedSources
, runLoopAndSourceKey
);
1376 CFDictionaryRemoveValue(sSharedSources
, stream
);
1378 _CFStreamSetSource(stream
, NULL
, count
== 0);
1380 __CFBitClear(stream
->flags
, SHARED_SOURCE
);
1382 __CFSpinUnlock(&sSourceLock
);
1384 CFRunLoopSourceRef source
= CFRunLoopSourceCreate(alloc
, 0, &ctxt
);
1385 _CFStreamSetSource(stream
, source
, FALSE
);
1386 CFRunLoopAddSource((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoopAndSourceKey
, 0), source
, (CFStringRef
)CFArrayGetValueAtIndex(runLoopAndSourceKey
, 1));
1387 CFRelease(runLoopAndSourceKey
);
1389 CFRunLoopAddSource(runLoop
, source
, runLoopMode
);
1393 /* We're not sharing, so just add the source to the rl & mode */
1394 CFRunLoopSourceRef source
= _CFStreamCopySource(stream
);
1396 CFRunLoopAddSource(runLoop
, source
, runLoopMode
);
1401 if (!stream
->client
->runLoopsAndModes
) {
1402 stream
->client
->runLoopsAndModes
= CFArrayCreateMutable(CFGetAllocator(stream
), 0, &kCFTypeArrayCallBacks
);
1404 CFArrayAppendValue(stream
->client
->runLoopsAndModes
, runLoop
);
1405 CFArrayAppendValue(stream
->client
->runLoopsAndModes
, runLoopMode
);
1408 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1409 cb
->schedule(stream
, runLoop
, runLoopMode
, _CFStreamGetInfoPointer(stream
));
1410 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1414 * If we've got events pending, we need to wake up and signal
1416 if (stream
->client
&& stream
->client
->whatToSignal
!= 0) {
1417 CFRunLoopSourceRef source
= _CFStreamCopySource(stream
);
1419 CFRunLoopSourceSignal(source
);
1421 _wakeUpRunLoop(stream
);
1426 CF_EXPORT
void CFReadStreamScheduleWithRunLoop(CFReadStreamRef stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1427 CF_OBJC_FUNCDISPATCH2(__kCFReadStreamTypeID
, void, stream
, "_scheduleInCFRunLoop:forMode:", runLoop
, runLoopMode
);
1428 _CFStreamScheduleWithRunLoop((struct _CFStream
*)stream
, runLoop
, runLoopMode
);
1431 CF_EXPORT
void CFWriteStreamScheduleWithRunLoop(CFWriteStreamRef stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1432 CF_OBJC_FUNCDISPATCH2(__kCFWriteStreamTypeID
, void, stream
, "_scheduleInCFRunLoop:forMode:", runLoop
, runLoopMode
);
1433 _CFStreamScheduleWithRunLoop((struct _CFStream
*)stream
, runLoop
, runLoopMode
);
1437 __private_extern__
void _CFStreamUnscheduleFromRunLoop(struct _CFStream
*stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1438 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1439 if (!stream
->client
) return;
1440 if (!stream
->client
->rlSource
) return;
1442 if (!__CFBitIsSet(stream
->flags
, SHARED_SOURCE
)) {
1443 CFRunLoopSourceRef source
= _CFStreamCopySource(stream
);
1445 CFRunLoopRemoveSource(runLoop
, source
, runLoopMode
);
1449 CFArrayRef runLoopAndSourceKey
;
1450 CFMutableArrayRef list
;
1453 __CFSpinLock(&sSourceLock
);
1455 runLoopAndSourceKey
= (CFArrayRef
)CFDictionaryGetValue(sSharedSources
, stream
);
1456 list
= (CFMutableArrayRef
)CFDictionaryGetValue(sSharedSources
, runLoopAndSourceKey
);
1458 count
= CFArrayGetCount(list
);
1459 i
= CFArrayGetFirstIndexOfValue(list
, CFRangeMake(0, count
), stream
);
1460 if (i
!= kCFNotFound
) {
1461 CFArrayRemoveValueAtIndex(list
, i
);
1466 CFRunLoopSourceRef source
= _CFStreamCopySource(stream
);
1468 CFRunLoopRemoveSource(runLoop
, source
, runLoopMode
);
1471 CFDictionaryRemoveValue(sSharedSources
, runLoopAndSourceKey
);
1474 CFDictionaryRemoveValue(sSharedSources
, stream
);
1476 _CFStreamSetSource(stream
, NULL
, count
== 0);
1478 __CFBitClear(stream
->flags
, SHARED_SOURCE
);
1480 __CFSpinUnlock(&sSourceLock
);
1483 _CFStreamRemoveRunLoopAndModeFromArray(stream
->client
->runLoopsAndModes
, runLoop
, runLoopMode
);
1485 if (cb
->unschedule
) {
1486 cb
->unschedule(stream
, runLoop
, runLoopMode
, _CFStreamGetInfoPointer(stream
));
1490 CF_EXPORT
void CFReadStreamUnscheduleFromRunLoop(CFReadStreamRef stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1491 CF_OBJC_FUNCDISPATCH2(__kCFReadStreamTypeID
, void, stream
, "_unscheduleFromCFRunLoop:forMode:", runLoop
, runLoopMode
);
1492 _CFStreamUnscheduleFromRunLoop((struct _CFStream
*)stream
, runLoop
, runLoopMode
);
1495 void CFWriteStreamUnscheduleFromRunLoop(CFWriteStreamRef stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1496 CF_OBJC_FUNCDISPATCH2(__kCFWriteStreamTypeID
, void, stream
, "_unscheduleFromCFRunLoop:forMode:", runLoop
, runLoopMode
);
1497 _CFStreamUnscheduleFromRunLoop((struct _CFStream
*)stream
, runLoop
, runLoopMode
);
1500 static void waitForOpen(struct _CFStream
*stream
) {
1501 CFRunLoopRef runLoop
= CFRunLoopGetCurrent();
1502 CFStringRef privateMode
= CFSTR("_kCFStreamBlockingOpenMode");
1503 _CFStreamScheduleWithRunLoop(stream
, runLoop
, privateMode
);
1504 // 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....
1505 while (__CFStreamGetStatus(stream
) == kCFStreamStatusOpening
) {
1506 CFRunLoopRunInMode(privateMode
, 1e+20, TRUE
);
1508 _CFStreamUnscheduleFromRunLoop(stream
, runLoop
, privateMode
);
1511 CF_INLINE CFArrayRef
_CFStreamGetRunLoopsAndModes(struct _CFStream
*stream
) {
1512 if (stream
->client
) return stream
->client
->runLoopsAndModes
;
1516 CF_EXPORT CFArrayRef
_CFReadStreamGetRunLoopsAndModes(CFReadStreamRef readStream
) {
1517 return _CFStreamGetRunLoopsAndModes((struct _CFStream
*)readStream
);
1520 CF_EXPORT CFArrayRef
_CFWriteStreamGetRunLoopsAndModes(CFWriteStreamRef writeStream
) {
1521 return _CFStreamGetRunLoopsAndModes((struct _CFStream
*)writeStream
);
1524 CF_EXPORT
void CFReadStreamSignalEvent(CFReadStreamRef stream
, CFStreamEventType event
, const void *error
) {
1525 _CFStreamSignalEvent((struct _CFStream
*)stream
, event
, (CFErrorRef
)error
, TRUE
);
1528 CF_EXPORT
void CFWriteStreamSignalEvent(CFWriteStreamRef stream
, CFStreamEventType event
, const void *error
) {
1529 _CFStreamSignalEvent((struct _CFStream
*)stream
, event
, (CFErrorRef
)error
, TRUE
);
1532 CF_EXPORT
void _CFReadStreamSignalEventDelayed(CFReadStreamRef stream
, CFStreamEventType event
, const void *error
) {
1533 _CFStreamSignalEvent((struct _CFStream
*)stream
, event
, (CFErrorRef
)error
, FALSE
);
1536 CF_EXPORT
void _CFReadStreamClearEvent(CFReadStreamRef readStream
, CFStreamEventType event
) {
1537 struct _CFStream
*stream
= (struct _CFStream
*)readStream
;
1538 if (stream
->client
) {
1539 stream
->client
->whatToSignal
&= ~event
;
1543 CF_EXPORT
void _CFWriteStreamSignalEventDelayed(CFWriteStreamRef stream
, CFStreamEventType event
, const void *error
) {
1544 _CFStreamSignalEvent((struct _CFStream
*)stream
, event
, (CFErrorRef
)error
, FALSE
);
1547 CF_EXPORT
void *CFReadStreamGetInfoPointer(CFReadStreamRef stream
) {
1548 return _CFStreamGetInfoPointer((struct _CFStream
*)stream
);
1551 CF_EXPORT
void *CFWriteStreamGetInfoPointer(CFWriteStreamRef stream
) {
1552 return _CFStreamGetInfoPointer((struct _CFStream
*)stream
);
1556 void _CFStreamSourceScheduleWithRunLoop(CFRunLoopSourceRef source
, CFMutableArrayRef runLoopsAndModes
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
)
1561 count
= CFArrayGetCount(runLoopsAndModes
);
1562 range
= CFRangeMake(0, count
);
1564 while (range
.length
) {
1566 CFIndex i
= CFArrayGetFirstIndexOfValue(runLoopsAndModes
, range
, runLoop
);
1568 if (i
== kCFNotFound
)
1571 if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes
, i
+ 1), runLoopMode
))
1574 range
.location
= i
+ 2;
1575 range
.length
= count
- range
.location
;
1578 // Add the new values.
1579 CFArrayAppendValue(runLoopsAndModes
, runLoop
);
1580 CFArrayAppendValue(runLoopsAndModes
, runLoopMode
);
1582 // Schedule the source on the new loop and mode.
1584 CFRunLoopAddSource(runLoop
, source
, runLoopMode
);
1589 void _CFStreamSourceUnscheduleFromRunLoop(CFRunLoopSourceRef source
, CFMutableArrayRef runLoopsAndModes
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
)
1594 count
= CFArrayGetCount(runLoopsAndModes
);
1595 range
= CFRangeMake(0, count
);
1597 while (range
.length
) {
1599 CFIndex i
= CFArrayGetFirstIndexOfValue(runLoopsAndModes
, range
, runLoop
);
1601 // If not found, it's not scheduled on it.
1602 if (i
== kCFNotFound
)
1605 // Make sure it is scheduled in this mode.
1606 if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes
, i
+ 1), runLoopMode
)) {
1608 // Remove mode and runloop from the list.
1609 CFArrayReplaceValues(runLoopsAndModes
, CFRangeMake(i
, 2), NULL
, 0);
1611 // Remove it from the runloop.
1613 CFRunLoopRemoveSource(runLoop
, source
, runLoopMode
);
1618 range
.location
= i
+ 2;
1619 range
.length
= count
- range
.location
;
1625 void _CFStreamSourceScheduleWithAllRunLoops(CFRunLoopSourceRef source
, CFArrayRef runLoopsAndModes
)
1627 CFIndex i
, count
= CFArrayGetCount(runLoopsAndModes
);
1632 for (i
= 0; i
< count
; i
+= 2) {
1634 // Make sure it's scheduled on all the right loops and modes.
1635 // Go through the array adding the source to all loops and modes.
1636 CFRunLoopAddSource((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoopsAndModes
, i
),
1638 (CFStringRef
)CFArrayGetValueAtIndex(runLoopsAndModes
, i
+ 1));
1644 void _CFStreamSourceUncheduleFromAllRunLoops(CFRunLoopSourceRef source
, CFArrayRef runLoopsAndModes
)
1646 CFIndex i
, count
= CFArrayGetCount(runLoopsAndModes
);
1651 for (i
= 0; i
< count
; i
+= 2) {
1653 // Go through the array removing the source from all loops and modes.
1654 CFRunLoopRemoveSource((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoopsAndModes
, i
),
1656 (CFStringRef
)CFArrayGetValueAtIndex(runLoopsAndModes
, i
+ 1));
1660 Boolean
_CFStreamRemoveRunLoopAndModeFromArray(CFMutableArrayRef runLoopsAndModes
, CFRunLoopRef rl
, CFStringRef mode
) {
1662 Boolean found
= FALSE
;
1664 if (!runLoopsAndModes
) return FALSE
;
1666 cnt
= CFArrayGetCount(runLoopsAndModes
);
1667 for (idx
= 0; idx
+ 1 < cnt
; idx
+= 2) {
1668 if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes
, idx
), rl
) && CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes
, idx
+ 1), mode
)) {
1669 CFArrayRemoveValueAtIndex(runLoopsAndModes
, idx
);
1670 CFArrayRemoveValueAtIndex(runLoopsAndModes
, idx
);
1678 // Used by NSStream to properly allocate the bridged objects
1679 CF_EXPORT CFIndex
_CFStreamInstanceSize(void) {
1680 return sizeof(struct _CFStream
);
1683 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1684 #elif DEPLOYMENT_TARGET_WINDOWS
1685 void __CFStreamCleanup(void) {
1686 __CFSpinLock(&sSourceLock
);
1687 if (sSharedSources
) {
1688 CFIndex count
= CFDictionaryGetCount(sSharedSources
);
1690 // Only release if empty. If it's still holding streams (which would be a client
1691 // bug leak), freeing this dict would free the streams, which then need to access the
1692 // dict to remove themselves, which leads to a deadlock.
1693 CFRelease(sSharedSources
);
1694 sSharedSources
= NULL
;
1696 const void ** keys
= (const void **)malloc(sizeof(const void *) * count
);
1700 CFDictionaryGetKeysAndValues(sSharedSources
, keys
, NULL
);
1701 fprintf(stderr
, "*** CFNetwork is shutting down, but %ld streams are still scheduled.\n", count
);
1703 for (i
= 0; i
< count
;i
++) {
1704 if ((CFGetTypeID(keys
[i
]) == __kCFReadStreamTypeID
) || (CFGetTypeID(keys
[i
]) == __kCFWriteStreamTypeID
)) {
1711 __CFSpinUnlock(&sSourceLock
);
1714 #error Unknown or unspecified DEPLOYMENT_TARGET