2 * Copyright (c) 2009 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@
24 Copyright (c) 2000-2009, Apple Inc. All rights reserved.
25 Responsibility: Becky Willrich
28 #include <CoreFoundation/CFRuntime.h>
29 #include <CoreFoundation/CFNumber.h>
31 #include "CFStreamInternal.h"
32 #include "CFInternal.h"
37 MIN_STATUS_CODE_BIT
= 0,
39 MAX_STATUS_CODE_BIT
= 4,
41 CONSTANT_CALLBACKS
= 5,
42 CALLING_CLIENT
= 6, // MUST remain 6 since it's value is used elsewhere.
46 // Values above used to be defined and others may rely on their values
48 // Values below should not matter if they are re-ordered or shift
54 /* 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
55 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 */
56 // Used in CFNetwork too
58 /* sSharesSources holds two mappings, one the inverse of the other, between a stream and the
59 RunLoop+RunLoopMode pair that it's scheduled in. If the stream is scheduled in more than
60 one loop or mode, it can't share RunLoopSources with others, and is not in this dict.
62 static CFSpinLock_t sSourceLock
= CFSpinLockInit
;
63 static CFMutableDictionaryRef sSharedSources
= NULL
;
65 static CFTypeID __kCFReadStreamTypeID
= _kCFRuntimeNotATypeID
;
66 static CFTypeID __kCFWriteStreamTypeID
= _kCFRuntimeNotATypeID
;
68 // Just reads the bits, for those cases where we don't want to go through any callback checking
69 #define __CFStreamGetStatus(x) __CFBitfieldGetValue((x)->flags, MAX_STATUS_CODE_BIT, MIN_STATUS_CODE_BIT)
71 __private_extern__ CFStreamStatus
_CFStreamGetStatus(struct _CFStream
*stream
);
72 static Boolean
_CFStreamRemoveRunLoopAndModeFromArray(CFMutableArrayRef runLoopsAndModes
, CFRunLoopRef rl
, CFStringRef mode
);
73 static void _wakeUpRunLoop(struct _CFStream
*stream
);
75 CF_INLINE
const struct _CFStreamCallBacks
*_CFStreamGetCallBackPtr(struct _CFStream
*stream
) {
76 return stream
->callBacks
;
79 CF_INLINE
void _CFStreamSetStatusCode(struct _CFStream
*stream
, CFStreamStatus newStatus
) {
80 CFStreamStatus status
= __CFStreamGetStatus(stream
);
81 if (((status
!= kCFStreamStatusClosed
) && (status
!= kCFStreamStatusError
)) ||
82 ((status
== kCFStreamStatusClosed
) && (newStatus
== kCFStreamStatusError
)))
84 __CFBitfieldSetValue(stream
->flags
, MAX_STATUS_CODE_BIT
, MIN_STATUS_CODE_BIT
, newStatus
);
88 CF_INLINE
void _CFStreamScheduleEvent(struct _CFStream
*stream
, CFStreamEventType event
) {
89 if (stream
->client
&& (stream
->client
->when
& event
) && stream
->client
->rlSource
) {
90 stream
->client
->whatToSignal
|= event
;
91 CFRunLoopSourceSignal(stream
->client
->rlSource
);
92 _wakeUpRunLoop(stream
);
96 CF_INLINE
void _CFStreamSetStreamError(struct _CFStream
*stream
, CFStreamError
*err
) {
98 stream
->error
= (CFErrorRef
)CFAllocatorAllocate(CFGetAllocator(stream
), sizeof(CFStreamError
), 0);
100 memmove(stream
->error
, err
, sizeof(CFStreamError
));
103 static CFStringRef
__CFStreamCopyDescription(CFTypeRef cf
) {
104 struct _CFStream
*stream
= (struct _CFStream
*)cf
;
105 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
106 CFStringRef contextDescription
;
108 if (cb
->copyDescription
) {
109 if (cb
->version
== 0) {
110 contextDescription
= ((CFStringRef(*)(void *))cb
->copyDescription
)(_CFStreamGetInfoPointer(stream
));
112 contextDescription
= cb
->copyDescription(stream
, _CFStreamGetInfoPointer(stream
));
115 contextDescription
= CFStringCreateWithFormat(CFGetAllocator(stream
), NULL
, CFSTR("info = %p"), _CFStreamGetInfoPointer(stream
));
117 if (CFGetTypeID(cf
) == __kCFReadStreamTypeID
) {
118 desc
= CFStringCreateWithFormat(CFGetAllocator(stream
), NULL
, CFSTR("<CFReadStream %p>{%@}"), stream
, contextDescription
);
120 desc
= CFStringCreateWithFormat(CFGetAllocator(stream
), NULL
, CFSTR("<CFWriteStream %p>{%@}"), stream
, contextDescription
);
122 CFRelease(contextDescription
);
126 __private_extern__
void _CFStreamClose(struct _CFStream
*stream
) {
127 CFStreamStatus status
= _CFStreamGetStatus(stream
);
128 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
129 if (status
== kCFStreamStatusNotOpen
|| status
== kCFStreamStatusClosed
|| (status
== kCFStreamStatusError
&& __CFBitIsSet(stream
->flags
, HAVE_CLOSED
))) {
130 // Stream is not open from the client's perspective; do not callout and do not update our status to "closed"
133 __CFBitSet(stream
->flags
, HAVE_CLOSED
);
134 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
136 cb
->close(stream
, _CFStreamGetInfoPointer(stream
));
138 if (stream
->client
&& stream
->client
->rlSource
) {
140 if (!__CFBitIsSet(stream
->flags
, SHARED_SOURCE
)) {
141 CFRunLoopSourceInvalidate(stream
->client
->rlSource
);
142 CFRelease(stream
->client
->rlSource
);
143 stream
->client
->rlSource
= NULL
;
147 CFArrayRef runLoopAndSourceKey
;
148 CFMutableArrayRef list
;
151 __CFSpinLock(&sSourceLock
);
153 runLoopAndSourceKey
= (CFArrayRef
)CFDictionaryGetValue(sSharedSources
, stream
);
154 list
= (CFMutableArrayRef
)CFDictionaryGetValue(sSharedSources
, runLoopAndSourceKey
);
156 c
= CFArrayGetCount(list
);
157 i
= CFArrayGetFirstIndexOfValue(list
, CFRangeMake(0, c
), stream
);
158 if (i
!= kCFNotFound
) {
159 CFArrayRemoveValueAtIndex(list
, i
);
163 CFAssert(CFArrayGetFirstIndexOfValue(list
, CFRangeMake(0, CFArrayGetCount(list
)), stream
) == kCFNotFound
, __kCFLogAssertion
, "CFStreamClose: stream found twice in its shared source's list");
166 CFRunLoopRemoveSource((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoopAndSourceKey
, 0), stream
->client
->rlSource
, (CFStringRef
)CFArrayGetValueAtIndex(runLoopAndSourceKey
, 1));
167 CFRunLoopSourceInvalidate(stream
->client
->rlSource
);
168 CFDictionaryRemoveValue(sSharedSources
, runLoopAndSourceKey
);
171 CFDictionaryRemoveValue(sSharedSources
, stream
);
173 CFRelease(stream
->client
->rlSource
);
174 stream
->client
->rlSource
= NULL
;
175 __CFBitClear(stream
->flags
, SHARED_SOURCE
);
177 __CFSpinUnlock(&sSourceLock
);
180 _CFStreamSetStatusCode(stream
, kCFStreamStatusClosed
);
181 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
184 //static int numStreamInstances = 0;
186 static void __CFStreamDeallocate(CFTypeRef cf
) {
187 struct _CFStream
*stream
= (struct _CFStream
*)cf
;
188 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
189 CFAllocatorRef alloc
= CFGetAllocator(stream
);
190 // numStreamInstances --;
193 _CFStreamClose(stream
);
195 if (stream
->client
) {
196 CFStreamClientContext
*cbContext
;
197 cbContext
= &(stream
->client
->cbContext
);
198 if (cbContext
->info
&& cbContext
->release
) {
199 cbContext
->release(cbContext
->info
);
201 if (stream
->client
->rlSource
) {
202 if (!__CFBitIsSet(stream
->flags
, SHARED_SOURCE
)) {
203 CFRunLoopSourceInvalidate(stream
->client
->rlSource
);
204 CFRelease(stream
->client
->rlSource
);
205 stream
->client
->rlSource
= NULL
;
209 CFArrayRef runLoopAndSourceKey
;
210 CFMutableArrayRef list
;
213 __CFSpinLock(&sSourceLock
);
215 runLoopAndSourceKey
= (CFArrayRef
)CFDictionaryGetValue(sSharedSources
, stream
);
216 list
= (CFMutableArrayRef
)CFDictionaryGetValue(sSharedSources
, runLoopAndSourceKey
);
218 c
= CFArrayGetCount(list
);
219 i
= CFArrayGetFirstIndexOfValue(list
, CFRangeMake(0, c
), stream
);
220 if (i
!= kCFNotFound
) {
221 CFArrayRemoveValueAtIndex(list
, i
);
226 CFRunLoopRemoveSource((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoopAndSourceKey
, 0), stream
->client
->rlSource
, (CFStringRef
)CFArrayGetValueAtIndex(runLoopAndSourceKey
, 1));
227 CFRunLoopSourceInvalidate(stream
->client
->rlSource
);
228 CFDictionaryRemoveValue(sSharedSources
, runLoopAndSourceKey
);
231 CFDictionaryRemoveValue(sSharedSources
, stream
);
233 CFRelease(stream
->client
->rlSource
);
234 stream
->client
->rlSource
= NULL
;
235 __CFBitClear(stream
->flags
, SHARED_SOURCE
);
237 __CFSpinUnlock(&sSourceLock
);
240 if (stream
->client
->runLoopsAndModes
) {
241 CFRelease(stream
->client
->runLoopsAndModes
);
244 CFAllocatorDeallocate(alloc
, stream
->client
);
245 stream
->client
= NULL
; // Just in case finalize, below, calls back in to us
248 if (cb
->version
== 0) {
249 ((void(*)(void *))cb
->finalize
)(_CFStreamGetInfoPointer(stream
));
251 cb
->finalize(stream
, _CFStreamGetInfoPointer(stream
));
255 if (cb
->version
< 2) {
256 CFAllocatorDeallocate(alloc
, stream
->error
);
258 CFRelease(stream
->error
);
261 if (!__CFBitIsSet(stream
->flags
, CONSTANT_CALLBACKS
)) {
262 CFAllocatorDeallocate(alloc
, (void *)stream
->callBacks
);
266 static const CFRuntimeClass __CFReadStreamClass
= {
271 __CFStreamDeallocate
,
274 NULL
, // copyHumanDesc
275 __CFStreamCopyDescription
278 static const CFRuntimeClass __CFWriteStreamClass
= {
283 __CFStreamDeallocate
,
286 NULL
, // copyHumanDesc
287 __CFStreamCopyDescription
290 CONST_STRING_DECL(kCFStreamPropertySocketNativeHandle
, "kCFStreamPropertySocketNativeHandle")
291 CONST_STRING_DECL(kCFStreamPropertySocketRemoteHostName
, "kCFStreamPropertySocketRemoteHostName")
292 CONST_STRING_DECL(kCFStreamPropertySocketRemotePortNumber
, "kCFStreamPropertySocketRemotePortNumber")
293 CONST_STRING_DECL(kCFStreamPropertyDataWritten
, "kCFStreamPropertyDataWritten")
294 CONST_STRING_DECL(kCFStreamPropertyAppendToFile
, "kCFStreamPropertyAppendToFile")
296 __private_extern__
void __CFStreamInitialize(void) {
297 __kCFReadStreamTypeID
= _CFRuntimeRegisterClass(&__CFReadStreamClass
);
298 __kCFWriteStreamTypeID
= _CFRuntimeRegisterClass(&__CFWriteStreamClass
);
302 CF_EXPORT CFTypeID
CFReadStreamGetTypeID(void) {
303 return __kCFReadStreamTypeID
;
306 CF_EXPORT CFTypeID
CFWriteStreamGetTypeID(void) {
307 return __kCFWriteStreamTypeID
;
310 static struct _CFStream
*_CFStreamCreate(CFAllocatorRef allocator
, Boolean isReadStream
) {
311 struct _CFStream
*newStream
= (struct _CFStream
*)_CFRuntimeCreateInstance(allocator
, isReadStream
? __kCFReadStreamTypeID
: __kCFWriteStreamTypeID
, sizeof(struct _CFStream
) - sizeof(CFRuntimeBase
), NULL
);
313 // numStreamInstances ++;
314 newStream
->flags
= 0;
315 _CFStreamSetStatusCode(newStream
, kCFStreamStatusNotOpen
);
316 newStream
->error
= NULL
;
317 newStream
->client
= NULL
;
318 newStream
->info
= NULL
;
319 newStream
->callBacks
= NULL
;
324 __private_extern__
struct _CFStream
*_CFStreamCreateWithConstantCallbacks(CFAllocatorRef alloc
, void *info
, const struct _CFStreamCallBacks
*cb
, Boolean isReading
) {
325 struct _CFStream
*newStream
;
326 if (cb
->version
!= 1) return NULL
;
327 newStream
= _CFStreamCreate(alloc
, isReading
);
329 __CFBitSet(newStream
->flags
, CONSTANT_CALLBACKS
);
330 newStream
->callBacks
= cb
;
332 newStream
->info
= cb
->create(newStream
, info
);
334 newStream
->info
= info
;
340 CF_EXPORT
void _CFStreamSetInfoPointer(struct _CFStream
*stream
, void *info
, const struct _CFStreamCallBacks
*cb
) {
341 if (info
!= stream
->info
) {
342 if (stream
->callBacks
->finalize
) {
343 stream
->callBacks
->finalize(stream
, stream
->info
);
346 stream
->info
= cb
->create(stream
, info
);
351 stream
->callBacks
= cb
;
355 CF_EXPORT CFReadStreamRef
CFReadStreamCreate(CFAllocatorRef alloc
, const CFReadStreamCallBacks
*callbacks
, void *info
) {
356 struct _CFStream
*newStream
= _CFStreamCreate(alloc
, TRUE
);
357 struct _CFStreamCallBacks
*cb
;
358 if (!newStream
) return NULL
;
359 cb
= (struct _CFStreamCallBacks
*)CFAllocatorAllocate(alloc
, sizeof(struct _CFStreamCallBacks
), 0);
361 CFRelease(newStream
);
364 if (callbacks
->version
== 0) {
365 CFReadStreamCallBacksV0
*cbV0
= (CFReadStreamCallBacksV0
*)callbacks
;
366 CFStreamClientContext
*ctxt
= (CFStreamClientContext
*)info
;
367 newStream
->info
= ctxt
->retain
? (void *)ctxt
->retain(ctxt
->info
) : ctxt
->info
;
369 cb
->create
= (void *(*)(struct _CFStream
*, void *))ctxt
->retain
;
370 cb
->finalize
= (void(*)(struct _CFStream
*, void *))ctxt
->release
;
371 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))ctxt
->copyDescription
;
372 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))cbV0
->open
;
373 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))cbV0
->openCompleted
;
374 cb
->read
= (CFIndex (*)(CFReadStreamRef
, UInt8
*, CFIndex
, CFErrorRef
*, Boolean
*, void *))cbV0
->read
;
375 cb
->getBuffer
= (const UInt8
*(*)(CFReadStreamRef
, CFIndex
, CFIndex
*, CFErrorRef
*, Boolean
*, void *))cbV0
->getBuffer
;
376 cb
->canRead
= (Boolean (*)(CFReadStreamRef
, CFErrorRef
*, void*))cbV0
->canRead
;
379 cb
->close
= (void (*)(struct _CFStream
*, void *))cbV0
->close
;
380 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))cbV0
->copyProperty
;
381 cb
->setProperty
= NULL
;
382 cb
->requestEvents
= NULL
;
383 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV0
->schedule
;
384 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV0
->unschedule
;
385 } else if (callbacks
->version
== 1) {
386 CFReadStreamCallBacksV1
*cbV1
= (CFReadStreamCallBacksV1
*)callbacks
;
387 newStream
->info
= cbV1
->create
? cbV1
->create((CFReadStreamRef
)newStream
, info
) : info
;
389 cb
->create
= (void *(*)(struct _CFStream
*, void *))cbV1
->create
;
390 cb
->finalize
= (void(*)(struct _CFStream
*, void *))cbV1
->finalize
;
391 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))cbV1
->copyDescription
;
392 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))cbV1
->open
;
393 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))cbV1
->openCompleted
;
394 cb
->read
= (CFIndex (*)(CFReadStreamRef
, UInt8
*, CFIndex
, CFErrorRef
*, Boolean
*, void *))cbV1
->read
;
395 cb
->getBuffer
= (const UInt8
*(*)(CFReadStreamRef
, CFIndex
, CFIndex
*, CFErrorRef
*, Boolean
*, void *))cbV1
->getBuffer
;
396 cb
->canRead
= (Boolean (*)(CFReadStreamRef
, CFErrorRef
*, void*))cbV1
->canRead
;
399 cb
->close
= (void (*)(struct _CFStream
*, void *))cbV1
->close
;
400 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))cbV1
->copyProperty
;
401 cb
->setProperty
= (Boolean(*)(struct _CFStream
*, CFStringRef
, CFTypeRef
, void *))cbV1
->setProperty
;
402 cb
->requestEvents
= (void(*)(struct _CFStream
*, CFOptionFlags
, void *))cbV1
->requestEvents
;
403 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV1
->schedule
;
404 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV1
->unschedule
;
406 newStream
->info
= callbacks
->create
? callbacks
->create((CFReadStreamRef
)newStream
, info
) : info
;
408 cb
->create
= (void *(*)(struct _CFStream
*, void *))callbacks
->create
;
409 cb
->finalize
= (void(*)(struct _CFStream
*, void *))callbacks
->finalize
;
410 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))callbacks
->copyDescription
;
411 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))callbacks
->open
;
412 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))callbacks
->openCompleted
;
413 cb
->read
= callbacks
->read
;
414 cb
->getBuffer
= callbacks
->getBuffer
;
415 cb
->canRead
= callbacks
->canRead
;
418 cb
->close
= (void (*)(struct _CFStream
*, void *))callbacks
->close
;
419 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))callbacks
->copyProperty
;
420 cb
->setProperty
= (Boolean(*)(struct _CFStream
*, CFStringRef
, CFTypeRef
, void *))callbacks
->setProperty
;
421 cb
->requestEvents
= (void(*)(struct _CFStream
*, CFOptionFlags
, void *))callbacks
->requestEvents
;
422 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))callbacks
->schedule
;
423 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))callbacks
->unschedule
;
426 newStream
->callBacks
= cb
;
427 return (CFReadStreamRef
)newStream
;
430 CF_EXPORT CFWriteStreamRef
CFWriteStreamCreate(CFAllocatorRef alloc
, const CFWriteStreamCallBacks
*callbacks
, void *info
) {
431 struct _CFStream
*newStream
= _CFStreamCreate(alloc
, FALSE
);
432 struct _CFStreamCallBacks
*cb
;
433 if (!newStream
) return NULL
;
434 cb
= (struct _CFStreamCallBacks
*)CFAllocatorAllocate(alloc
, sizeof(struct _CFStreamCallBacks
), 0);
436 CFRelease(newStream
);
439 if (callbacks
->version
== 0) {
440 CFWriteStreamCallBacksV0
*cbV0
= (CFWriteStreamCallBacksV0
*)callbacks
;
441 CFStreamClientContext
*ctxt
= (CFStreamClientContext
*)info
;
442 newStream
->info
= ctxt
->retain
? (void *)ctxt
->retain(ctxt
->info
) : ctxt
->info
;
444 cb
->create
= (void *(*)(struct _CFStream
*, void *))ctxt
->retain
;
445 cb
->finalize
= (void(*)(struct _CFStream
*, void *))ctxt
->release
;
446 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))ctxt
->copyDescription
;
447 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))cbV0
->open
;
448 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))cbV0
->openCompleted
;
450 cb
->getBuffer
= NULL
;
452 cb
->write
= (CFIndex(*)(CFWriteStreamRef stream
, const UInt8
*buffer
, CFIndex bufferLength
, CFErrorRef
*error
, void *info
))cbV0
->write
;
453 cb
->canWrite
= (Boolean(*)(CFWriteStreamRef stream
, CFErrorRef
*error
, void *info
))cbV0
->canWrite
;
454 cb
->close
= (void (*)(struct _CFStream
*, void *))cbV0
->close
;
455 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))cbV0
->copyProperty
;
456 cb
->setProperty
= NULL
;
457 cb
->requestEvents
= NULL
;
458 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV0
->schedule
;
459 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV0
->unschedule
;
460 } else if (callbacks
->version
== 1) {
461 CFWriteStreamCallBacksV1
*cbV1
= (CFWriteStreamCallBacksV1
*)callbacks
;
463 newStream
->info
= cbV1
->create
? cbV1
->create((CFWriteStreamRef
)newStream
, info
) : info
;
464 cb
->create
= (void *(*)(struct _CFStream
*, void *))cbV1
->create
;
465 cb
->finalize
= (void(*)(struct _CFStream
*, void *))cbV1
->finalize
;
466 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))cbV1
->copyDescription
;
467 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))cbV1
->open
;
468 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))cbV1
->openCompleted
;
470 cb
->getBuffer
= NULL
;
472 cb
->write
= (CFIndex(*)(CFWriteStreamRef stream
, const UInt8
*buffer
, CFIndex bufferLength
, CFErrorRef
*error
, void *info
))cbV1
->write
;
473 cb
->canWrite
= (Boolean(*)(CFWriteStreamRef stream
, CFErrorRef
*error
, void *info
))cbV1
->canWrite
;
474 cb
->close
= (void (*)(struct _CFStream
*, void *))cbV1
->close
;
475 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))cbV1
->copyProperty
;
476 cb
->setProperty
= (Boolean (*)(struct _CFStream
*, CFStringRef
, CFTypeRef
, void *))cbV1
->setProperty
;
477 cb
->requestEvents
= (void(*)(struct _CFStream
*, CFOptionFlags
, void *))cbV1
->requestEvents
;
478 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV1
->schedule
;
479 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV1
->unschedule
;
481 cb
->version
= callbacks
->version
;
482 newStream
->info
= callbacks
->create
? callbacks
->create((CFWriteStreamRef
)newStream
, info
) : info
;
483 cb
->create
= (void *(*)(struct _CFStream
*, void *))callbacks
->create
;
484 cb
->finalize
= (void(*)(struct _CFStream
*, void *))callbacks
->finalize
;
485 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))callbacks
->copyDescription
;
486 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))callbacks
->open
;
487 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))callbacks
->openCompleted
;
489 cb
->getBuffer
= NULL
;
491 cb
->write
= callbacks
->write
;
492 cb
->canWrite
= callbacks
->canWrite
;
493 cb
->close
= (void (*)(struct _CFStream
*, void *))callbacks
->close
;
494 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))callbacks
->copyProperty
;
495 cb
->setProperty
= (Boolean (*)(struct _CFStream
*, CFStringRef
, CFTypeRef
, void *))callbacks
->setProperty
;
496 cb
->requestEvents
= (void(*)(struct _CFStream
*, CFOptionFlags
, void *))callbacks
->requestEvents
;
497 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))callbacks
->schedule
;
498 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))callbacks
->unschedule
;
500 newStream
->callBacks
= cb
;
501 return (CFWriteStreamRef
)newStream
;
504 static void _signalEventSync(struct _CFStream
* stream
, CFOptionFlags whatToSignal
)
506 CFOptionFlags eventMask
;
508 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
511 void (*release
) (void*) = NULL
;
513 if (stream
->client
->cbContext
.retain
== NULL
)
514 info
= stream
->client
->cbContext
.info
;
516 info
= stream
->client
->cbContext
.retain(stream
->client
->cbContext
.info
);
517 release
= stream
->client
->cbContext
.release
;
520 for (eventMask
= 1; eventMask
<= whatToSignal
; eventMask
= eventMask
<< 1) {
521 if ((eventMask
& whatToSignal
) && (stream
->client
->when
& eventMask
)) {
522 stream
->client
->cb(stream
, eventMask
, info
);
524 /* What happens if the callback sets the client to NULL? We're in a loop here... Hmm. */
525 /* After writing that comment, I see: <rdar://problem/6793636> CFReadStreamSetClient(..., NULL) unsafely releases info pointer immediately */
532 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
535 static void _cfstream_solo_signalEventSync(void* info
)
537 CFTypeID typeID
= CFGetTypeID((CFTypeRef
) info
);
539 if (typeID
!= CFReadStreamGetTypeID() && typeID
!= CFWriteStreamGetTypeID()) {
540 CFLog(__kCFLogAssertion
, CFSTR("Expected an read or write stream for %p"), info
);
545 struct _CFStream
* stream
= (struct _CFStream
*) info
;
546 CFOptionFlags whatToSignal
= stream
->client
->whatToSignal
;
547 stream
->client
->whatToSignal
= 0;
549 /* Since the array version holds a retain, we do it here as well, as opposed to taking a second retain in the client callback */
551 _signalEventSync(stream
, whatToSignal
);
556 static void _cfstream_shared_signalEventSync(void* info
)
558 CFTypeID typeID
= CFGetTypeID((CFTypeRef
) info
);
560 if (typeID
!= CFArrayGetTypeID()) {
561 CFLog(__kCFLogAssertion
, CFSTR("Expected an array for %p"), info
);
566 CFMutableArrayRef list
= (CFMutableArrayRef
) info
;
568 CFOptionFlags whatToSignal
= 0;
569 struct _CFStream
* stream
= NULL
;
571 __CFSpinLock(&sSourceLock
);
573 /* Looks like, we grab the first stream that wants an event... */
574 /* Note that I grab an extra retain when I pull out the stream here... */
575 c
= CFArrayGetCount(list
);
576 for (i
= 0; i
< c
; i
++) {
577 struct _CFStream
* s
= (struct _CFStream
*)CFArrayGetValueAtIndex(list
, i
);
579 if (s
->client
->whatToSignal
) {
582 whatToSignal
= stream
->client
->whatToSignal
;
583 s
->client
->whatToSignal
= 0;
588 /* And then we also signal any other streams in this array so that we get them next go? */
590 struct _CFStream
* s
= (struct _CFStream
*)CFArrayGetValueAtIndex(list
, i
);
591 if (s
->client
->whatToSignal
) {
592 CFRunLoopSourceSignal(s
->client
->rlSource
);
597 __CFSpinUnlock(&sSourceLock
);
599 /* We're sitting here now, possibly with a stream that needs to be processed by the common routine */
601 _signalEventSync(stream
, whatToSignal
);
603 /* Lose our extra retain */
609 // 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
610 // are likely to signal the same run loop over and over again. Don't know if we should worry about that.
611 static void _wakeUpRunLoop(struct _CFStream
*stream
) {
612 CFRunLoopRef rl
= NULL
;
615 if (!stream
->client
|| !stream
->client
->runLoopsAndModes
) return;
616 rlArray
= stream
->client
->runLoopsAndModes
;
617 cnt
= CFArrayGetCount(rlArray
);
618 if (cnt
== 0) return;
620 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, 0);
622 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, 0);
623 for (idx
= 2; NULL
!= rl
&& idx
< cnt
; idx
+=2) {
624 CFRunLoopRef value
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, idx
);
625 if (value
!= rl
) rl
= NULL
;
627 if (NULL
== rl
) { /* more than one different rl, so we must pick one */
628 for (idx
= 0; idx
< cnt
; idx
+=2) {
629 CFRunLoopRef value
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, idx
);
630 CFStringRef currentMode
= CFRunLoopCopyCurrentMode(value
);
631 if (NULL
!= currentMode
&& CFEqual(currentMode
, CFArrayGetValueAtIndex(rlArray
, idx
+1)) && CFRunLoopIsWaiting(value
)) {
632 CFRelease(currentMode
);
636 if (NULL
!= currentMode
) CFRelease(currentMode
);
638 if (NULL
== rl
) { /* didn't choose one above, so choose first */
639 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, 0);
643 if (NULL
!= rl
&& CFRunLoopIsWaiting(rl
)) CFRunLoopWakeUp(rl
);
646 __private_extern__
void _CFStreamSignalEvent(struct _CFStream
*stream
, CFStreamEventType event
, CFErrorRef error
, Boolean synchronousAllowed
) {
647 // Update our internal status; we must use the primitive __CFStreamGetStatus(), because CFStreamGetStatus() calls us, and we can end up in an infinite loop.
648 CFStreamStatus status
= __CFStreamGetStatus(stream
);
650 // Sanity check the event
651 if (status
== kCFStreamStatusNotOpen
) {
652 // No events allowed; this is almost certainly a bug in the stream's implementation
653 CFLog(__kCFLogAssertion
, CFSTR("Stream %p is sending an event before being opened"), stream
);
655 } else if (status
== kCFStreamStatusClosed
|| status
== kCFStreamStatusError
) {
656 // no further events are allowed
658 } else if (status
== kCFStreamStatusAtEnd
) {
659 // Only error events are allowed
660 event
&= kCFStreamEventErrorOccurred
;
661 } else if (status
!= kCFStreamStatusOpening
) {
662 // cannot send open completed; that happened already
663 event
&= ~kCFStreamEventOpenCompleted
;
666 // Change status if appropriate
667 if (event
& kCFStreamEventOpenCompleted
&& status
== kCFStreamStatusOpening
) {
668 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
670 if (event
& kCFStreamEventEndEncountered
&& status
< kCFStreamStatusAtEnd
) {
671 _CFStreamSetStatusCode(stream
, kCFStreamStatusAtEnd
);
673 if (event
& kCFStreamEventErrorOccurred
) {
674 if (_CFStreamGetCallBackPtr(stream
)->version
< 2) {
675 _CFStreamSetStreamError(stream
, (CFStreamError
*)error
);
677 CFAssert(error
, __kCFLogAssertion
, "CFStream: kCFStreamEventErrorOccurred signalled, but error is NULL!");
679 if (stream
->error
) CFRelease(stream
->error
);
680 stream
->error
= error
;
682 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
685 // Now signal any pertinent event
686 if (stream
->client
&& stream
->client
->rlSource
&& (stream
->client
->when
& event
)) {
688 Boolean signalNow
= FALSE
;
690 stream
->client
->whatToSignal
|= event
;
692 if (synchronousAllowed
&& !__CFBitIsSet(stream
->flags
, CALLING_CLIENT
)) {
694 CFRunLoopRef rl
= CFRunLoopGetCurrent();
695 CFStringRef mode
= CFRunLoopCopyCurrentMode(rl
);
698 if (CFRunLoopContainsSource(rl
, stream
->client
->rlSource
, mode
))
705 // Can call out safely right now
706 _cfstream_solo_signalEventSync(stream
);
708 // Schedule for later delivery
709 CFRunLoopSourceSignal(stream
->client
->rlSource
);
710 _wakeUpRunLoop(stream
);
715 __private_extern__ CFStreamStatus
_CFStreamGetStatus(struct _CFStream
*stream
) {
716 CFStreamStatus status
= __CFStreamGetStatus(stream
);
717 // 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.
718 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
719 if (status
== kCFStreamStatusOpening
) {
720 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
721 if (cb
->openCompleted
) {
723 if (cb
->version
< 2) {
724 CFStreamError err
= {0, 0};
725 isComplete
= ((_CFStreamCBOpenCompletedV1
)(cb
->openCompleted
))(stream
, &err
, _CFStreamGetInfoPointer(stream
));
726 if (err
.error
!= 0) _CFStreamSetStreamError(stream
, &err
);
728 isComplete
= cb
->openCompleted(stream
, &(stream
->error
), _CFStreamGetInfoPointer(stream
));
731 if (!stream
->error
) {
732 status
= kCFStreamStatusOpen
;
734 status
= kCFStreamStatusError
;
736 _CFStreamSetStatusCode(stream
, status
);
737 if (status
== kCFStreamStatusOpen
) {
738 _CFStreamScheduleEvent(stream
, kCFStreamEventOpenCompleted
);
740 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
745 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
749 CF_EXPORT CFStreamStatus
CFReadStreamGetStatus(CFReadStreamRef stream
) {
750 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID
, CFStreamStatus
, stream
, "streamStatus");
751 return _CFStreamGetStatus((struct _CFStream
*)stream
);
754 CF_EXPORT CFStreamStatus
CFWriteStreamGetStatus(CFWriteStreamRef stream
) {
755 CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID
, CFStreamStatus
, stream
, "streamStatus");
756 return _CFStreamGetStatus((struct _CFStream
*)stream
);
759 static CFStreamError
_CFStreamGetStreamError(struct _CFStream
*stream
) {
760 CFStreamError result
;
761 if (!stream
->error
) {
764 } else if (_CFStreamGetCallBackPtr(stream
)->version
< 2) {
765 CFStreamError
*streamError
= (CFStreamError
*)(stream
->error
);
766 result
.error
= streamError
->error
;
767 result
.domain
= streamError
->domain
;
769 result
= _CFStreamErrorFromError(stream
->error
);
774 CF_EXPORT CFStreamError
CFReadStreamGetError(CFReadStreamRef stream
) {
775 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID
, CFStreamError
, stream
, "_cfStreamError");
776 return _CFStreamGetStreamError((struct _CFStream
*)stream
);
779 CF_EXPORT CFStreamError
CFWriteStreamGetError(CFWriteStreamRef stream
) {
780 CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID
, CFStreamError
, stream
, "_cfStreamError");
781 return _CFStreamGetStreamError((struct _CFStream
*)stream
);
784 static CFErrorRef
_CFStreamCopyError(struct _CFStream
*stream
) {
785 if (!stream
->error
) {
787 } else if (_CFStreamGetCallBackPtr(stream
)->version
< 2) {
788 return _CFErrorFromStreamError(CFGetAllocator(stream
), (CFStreamError
*)(stream
->error
));
790 CFRetain(stream
->error
);
791 return stream
->error
;
795 CF_EXPORT CFErrorRef
CFReadStreamCopyError(CFReadStreamRef stream
) {
796 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID
, CFErrorRef
, stream
, "streamError");
797 return _CFStreamCopyError((struct _CFStream
*)stream
);
800 CF_EXPORT CFErrorRef
CFWriteStreamCopyError(CFWriteStreamRef stream
) {
801 return _CFStreamCopyError((struct _CFStream
*)stream
);
802 CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID
, CFErrorRef
, stream
, "streamError");
805 __private_extern__ Boolean
_CFStreamOpen(struct _CFStream
*stream
) {
806 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
807 Boolean success
, openComplete
;
808 if (_CFStreamGetStatus(stream
) != kCFStreamStatusNotOpen
) {
811 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
812 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpening
);
814 if (cb
->version
< 2) {
815 CFStreamError err
= {0, 0};
816 success
= ((_CFStreamCBOpenV1
)(cb
->open
))(stream
, &err
, &openComplete
, _CFStreamGetInfoPointer(stream
));
817 if (err
.error
!= 0) _CFStreamSetStreamError(stream
, &err
);
819 success
= cb
->open(stream
, &(stream
->error
), &openComplete
, _CFStreamGetInfoPointer(stream
));
827 // 2957690 - Guard against the possibility that the stream has already signalled itself in to a later state (like AtEnd)
828 if (__CFStreamGetStatus(stream
) == kCFStreamStatusOpening
) {
829 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
831 _CFStreamScheduleEvent(stream
, kCFStreamEventOpenCompleted
);
833 #if DEPLOYMENT_TARGET_WINDOWS
834 _CFStreamClose(stream
);
836 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
837 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
840 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
844 CF_EXPORT Boolean
CFReadStreamOpen(CFReadStreamRef stream
) {
845 if(CF_IS_OBJC(__kCFReadStreamTypeID
, stream
)) {
846 CF_OBJC_VOIDCALL0(stream
, "open");
849 return _CFStreamOpen((struct _CFStream
*)stream
);
852 CF_EXPORT Boolean
CFWriteStreamOpen(CFWriteStreamRef stream
) {
853 if(CF_IS_OBJC(__kCFWriteStreamTypeID
, stream
)) {
854 CF_OBJC_VOIDCALL0(stream
, "open");
857 return _CFStreamOpen((struct _CFStream
*)stream
);
860 CF_EXPORT
void CFReadStreamClose(CFReadStreamRef stream
) {
861 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID
, void, stream
, "close");
862 _CFStreamClose((struct _CFStream
*)stream
);
865 CF_EXPORT
void CFWriteStreamClose(CFWriteStreamRef stream
) {
866 CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID
, void, stream
, "close");
867 _CFStreamClose((struct _CFStream
*)stream
);
870 CF_EXPORT Boolean
CFReadStreamHasBytesAvailable(CFReadStreamRef readStream
) {
871 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID
, Boolean
, readStream
, "hasBytesAvailable");
872 struct _CFStream
*stream
= (struct _CFStream
*)readStream
;
873 CFStreamStatus status
= _CFStreamGetStatus(stream
);
874 const struct _CFStreamCallBacks
*cb
;
875 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusReading
) {
878 cb
= _CFStreamGetCallBackPtr(stream
);
879 if (cb
->canRead
== NULL
) {
880 return TRUE
; // No way to know without trying....
883 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
884 if (cb
->version
< 2) {
885 result
= ((_CFStreamCBCanReadV1
)(cb
->canRead
))((CFReadStreamRef
)stream
, _CFStreamGetInfoPointer(stream
));
887 result
= cb
->canRead((CFReadStreamRef
)stream
, &(stream
->error
), _CFStreamGetInfoPointer(stream
));
889 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
890 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
893 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
898 static void waitForOpen(struct _CFStream
*stream
);
899 CFIndex
CFReadStreamRead(CFReadStreamRef readStream
, UInt8
*buffer
, CFIndex bufferLength
) {
900 CF_OBJC_FUNCDISPATCH2(__kCFReadStreamTypeID
, CFIndex
, readStream
, "read:maxLength:", buffer
, bufferLength
);
901 struct _CFStream
*stream
= (struct _CFStream
*)readStream
;
902 CFStreamStatus status
= _CFStreamGetStatus(stream
);
903 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
904 if (status
== kCFStreamStatusOpening
) {
905 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
907 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
908 status
= _CFStreamGetStatus(stream
);
911 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusReading
&& status
!= kCFStreamStatusAtEnd
) {
913 } else if (status
== kCFStreamStatusAtEnd
) {
918 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
919 if (stream
->client
) {
920 stream
->client
->whatToSignal
&= ~kCFStreamEventHasBytesAvailable
;
922 _CFStreamSetStatusCode(stream
, kCFStreamStatusReading
);
923 if (cb
->version
< 2) {
924 CFStreamError err
= {0, 0};
925 bytesRead
= ((_CFStreamCBReadV1
)(cb
->read
))((CFReadStreamRef
)stream
, buffer
, bufferLength
, &err
, &atEOF
, _CFStreamGetInfoPointer(stream
));
926 if (err
.error
!= 0) _CFStreamSetStreamError(stream
, &err
);
928 bytesRead
= cb
->read((CFReadStreamRef
)stream
, buffer
, bufferLength
, &(stream
->error
), &atEOF
, _CFStreamGetInfoPointer(stream
));
932 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
933 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
935 _CFStreamSetStatusCode(stream
, kCFStreamStatusAtEnd
);
936 _CFStreamScheduleEvent(stream
, kCFStreamEventEndEncountered
);
938 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
940 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
945 CF_EXPORT
const UInt8
*CFReadStreamGetBuffer(CFReadStreamRef readStream
, CFIndex maxBytesToRead
, CFIndex
*numBytesRead
) {
946 if (CF_IS_OBJC(__kCFReadStreamTypeID
, readStream
)) {
947 uint8_t *bufPtr
= NULL
;
949 CF_OBJC_CALL2(Boolean
, gotBytes
, readStream
, "getBuffer:length:", &bufPtr
, numBytesRead
);
951 return (const UInt8
*)bufPtr
;
956 struct _CFStream
*stream
= (struct _CFStream
*)readStream
;
957 CFStreamStatus status
= _CFStreamGetStatus(stream
);
958 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
960 if (status
== kCFStreamStatusOpening
) {
961 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
963 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
964 status
= _CFStreamGetStatus(stream
);
966 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusReading
&& status
!= kCFStreamStatusAtEnd
) {
969 } else if (status
== kCFStreamStatusAtEnd
|| cb
->getBuffer
== NULL
) {
974 Boolean hadBytes
= stream
->client
&& (stream
->client
->whatToSignal
& kCFStreamEventHasBytesAvailable
);
975 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
977 stream
->client
->whatToSignal
&= ~kCFStreamEventHasBytesAvailable
;
979 _CFStreamSetStatusCode(stream
, kCFStreamStatusReading
);
980 if (cb
->version
< 2) {
981 CFStreamError err
= {0, 0};
982 buffer
= ((_CFStreamCBGetBufferV1
)(cb
->getBuffer
))((CFReadStreamRef
)stream
, maxBytesToRead
, numBytesRead
, &err
, &atEOF
, _CFStreamGetInfoPointer(stream
));
983 if (err
.error
!= 0) _CFStreamSetStreamError(stream
, &err
);
985 buffer
= cb
->getBuffer((CFReadStreamRef
)stream
, maxBytesToRead
, numBytesRead
, &(stream
->error
), &atEOF
, _CFStreamGetInfoPointer(stream
));
989 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
991 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
993 _CFStreamSetStatusCode(stream
, kCFStreamStatusAtEnd
);
994 _CFStreamScheduleEvent(stream
, kCFStreamEventEndEncountered
);
996 if (!buffer
&& hadBytes
) {
997 stream
->client
->whatToSignal
|= kCFStreamEventHasBytesAvailable
;
999 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
1001 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1006 CF_EXPORT Boolean
CFWriteStreamCanAcceptBytes(CFWriteStreamRef writeStream
) {
1007 CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID
, Boolean
, writeStream
, "hasSpaceAvailable");
1008 struct _CFStream
*stream
= (struct _CFStream
*)writeStream
;
1009 CFStreamStatus status
= _CFStreamGetStatus(stream
);
1010 const struct _CFStreamCallBacks
*cb
;
1011 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusWriting
) {
1014 cb
= _CFStreamGetCallBackPtr(stream
);
1015 if (cb
->canWrite
== NULL
) {
1016 return TRUE
; // No way to know without trying....
1019 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1020 if (cb
->version
< 2) {
1021 result
= ((_CFStreamCBCanWriteV1
)(cb
->canWrite
))((CFWriteStreamRef
)stream
, _CFStreamGetInfoPointer(stream
));
1023 result
= cb
->canWrite((CFWriteStreamRef
)stream
, &(stream
->error
), _CFStreamGetInfoPointer(stream
));
1024 if (stream
->error
) {
1025 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
1026 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
1029 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1034 CF_EXPORT CFIndex
CFWriteStreamWrite(CFWriteStreamRef writeStream
, const UInt8
*buffer
, CFIndex bufferLength
) {
1035 CF_OBJC_FUNCDISPATCH2(__kCFWriteStreamTypeID
, CFIndex
, writeStream
, "write:maxLength:", buffer
, bufferLength
);
1036 struct _CFStream
*stream
= (struct _CFStream
*)writeStream
;
1037 CFStreamStatus status
= _CFStreamGetStatus(stream
);
1038 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1039 if (status
== kCFStreamStatusOpening
) {
1040 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1041 waitForOpen(stream
);
1042 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1043 status
= _CFStreamGetStatus(stream
);
1045 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusWriting
) {
1049 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1050 _CFStreamSetStatusCode(stream
, kCFStreamStatusWriting
);
1051 if (stream
->client
) {
1052 stream
->client
->whatToSignal
&= ~kCFStreamEventCanAcceptBytes
;
1054 if (cb
->version
< 2) {
1055 CFStreamError err
= {0, 0};
1056 result
= ((_CFStreamCBWriteV1
)(cb
->write
))((CFWriteStreamRef
)stream
, buffer
, bufferLength
, &err
, _CFStreamGetInfoPointer(stream
));
1057 if (err
.error
) _CFStreamSetStreamError(stream
, &err
);
1059 result
= cb
->write((CFWriteStreamRef
)stream
, buffer
, bufferLength
, &(stream
->error
), _CFStreamGetInfoPointer(stream
));
1061 if (stream
->error
) {
1062 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
1063 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
1064 } else if (result
== 0) {
1065 _CFStreamSetStatusCode(stream
, kCFStreamStatusAtEnd
);
1066 _CFStreamScheduleEvent(stream
, kCFStreamEventEndEncountered
);
1068 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
1070 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1075 __private_extern__ CFTypeRef
_CFStreamCopyProperty(struct _CFStream
*stream
, CFStringRef propertyName
) {
1076 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1077 if (cb
->copyProperty
== NULL
) {
1081 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1082 result
= cb
->copyProperty(stream
, propertyName
, _CFStreamGetInfoPointer(stream
));
1083 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1088 CF_EXPORT CFTypeRef
CFReadStreamCopyProperty(CFReadStreamRef stream
, CFStringRef propertyName
) {
1089 CF_OBJC_FUNCDISPATCH1(__kCFReadStreamTypeID
, CFTypeRef
, stream
, "propertyForKey:", propertyName
);
1090 return _CFStreamCopyProperty((struct _CFStream
*)stream
, propertyName
);
1093 CF_EXPORT CFTypeRef
CFWriteStreamCopyProperty(CFWriteStreamRef stream
, CFStringRef propertyName
) {
1094 CF_OBJC_FUNCDISPATCH1(__kCFWriteStreamTypeID
, CFTypeRef
, stream
, "propertyForKey:", propertyName
);
1095 return _CFStreamCopyProperty((struct _CFStream
*)stream
, propertyName
);
1098 __private_extern__ Boolean
_CFStreamSetProperty(struct _CFStream
*stream
, CFStringRef prop
, CFTypeRef val
) {
1099 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1100 if (cb
->setProperty
== NULL
) {
1104 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1105 result
= cb
->setProperty(stream
, prop
, val
, _CFStreamGetInfoPointer(stream
));
1106 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1112 Boolean
CFReadStreamSetProperty(CFReadStreamRef stream
, CFStringRef propertyName
, CFTypeRef propertyValue
) {
1113 CF_OBJC_FUNCDISPATCH2(__kCFReadStreamTypeID
, Boolean
, stream
, "setProperty:forKey:", propertyValue
, propertyName
);
1114 return _CFStreamSetProperty((struct _CFStream
*)stream
, propertyName
, propertyValue
);
1118 Boolean
CFWriteStreamSetProperty(CFWriteStreamRef stream
, CFStringRef propertyName
, CFTypeRef propertyValue
) {
1119 CF_OBJC_FUNCDISPATCH2(__kCFWriteStreamTypeID
, Boolean
, stream
, "setProperty:forKey:", propertyValue
, propertyName
);
1120 return _CFStreamSetProperty((struct _CFStream
*)stream
, propertyName
, propertyValue
);
1123 static void _initializeClient(struct _CFStream
*stream
) {
1124 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1125 if (!cb
->schedule
) return; // Do we wish to allow this?
1126 stream
->client
= (struct _CFStreamClient
*)CFAllocatorAllocate(CFGetAllocator(stream
), sizeof(struct _CFStreamClient
), 0);
1127 memset(stream
->client
, 0, sizeof(struct _CFStreamClient
));
1130 /* If we add a setClient callback to the concrete stream callbacks, we must set/clear CALLING_CLIENT around it */
1131 __private_extern__ Boolean
_CFStreamSetClient(struct _CFStream
*stream
, CFOptionFlags streamEvents
, void (*clientCB
)(struct _CFStream
*, CFStreamEventType
, void *), CFStreamClientContext
*clientCallBackContext
) {
1133 Boolean removingClient
= (streamEvents
== kCFStreamEventNone
|| clientCB
== NULL
|| clientCallBackContext
== NULL
);
1134 if (removingClient
) {
1136 streamEvents
= kCFStreamEventNone
;
1137 clientCallBackContext
= NULL
;
1139 if (!stream
->client
) {
1140 if (removingClient
) {
1141 // We have no client now, and we've been asked to add none???
1144 _initializeClient(stream
);
1145 if (!stream
->client
) {
1146 // Asynch not supported
1150 if (stream
->client
->cb
&& stream
->client
->cbContext
.release
) {
1151 stream
->client
->cbContext
.release(stream
->client
->cbContext
.info
);
1153 stream
->client
->cb
= clientCB
;
1154 if (clientCallBackContext
) {
1155 stream
->client
->cbContext
.version
= clientCallBackContext
->version
;
1156 stream
->client
->cbContext
.retain
= clientCallBackContext
->retain
;
1157 stream
->client
->cbContext
.release
= clientCallBackContext
->release
;
1158 stream
->client
->cbContext
.copyDescription
= clientCallBackContext
->copyDescription
;
1159 stream
->client
->cbContext
.info
= (clientCallBackContext
->retain
&& clientCallBackContext
->info
) ? clientCallBackContext
->retain(clientCallBackContext
->info
) : clientCallBackContext
->info
;
1161 stream
->client
->cbContext
.retain
= NULL
;
1162 stream
->client
->cbContext
.release
= NULL
;
1163 stream
->client
->cbContext
.copyDescription
= NULL
;
1164 stream
->client
->cbContext
.info
= NULL
;
1166 if (stream
->client
->when
!= streamEvents
) {
1167 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1168 stream
->client
->when
= streamEvents
;
1169 if (cb
->requestEvents
) {
1170 cb
->requestEvents(stream
, streamEvents
, _CFStreamGetInfoPointer(stream
));
1176 CF_EXPORT Boolean
CFReadStreamSetClient(CFReadStreamRef readStream
, CFOptionFlags streamEvents
, CFReadStreamClientCallBack clientCB
, CFStreamClientContext
*clientContext
) {
1177 CF_OBJC_FUNCDISPATCH3(__kCFReadStreamTypeID
, Boolean
, readStream
, "_setCFClientFlags:callback:context:", streamEvents
, clientCB
, clientContext
);
1178 streamEvents
&= ~kCFStreamEventCanAcceptBytes
;
1179 return _CFStreamSetClient((struct _CFStream
*)readStream
, streamEvents
, (void (*)(struct _CFStream
*, CFStreamEventType
, void *))clientCB
, clientContext
);
1182 CF_EXPORT Boolean
CFWriteStreamSetClient(CFWriteStreamRef writeStream
, CFOptionFlags streamEvents
, CFWriteStreamClientCallBack clientCB
, CFStreamClientContext
*clientContext
) {
1183 CF_OBJC_FUNCDISPATCH3(__kCFWriteStreamTypeID
, Boolean
, writeStream
, "_setCFClientFlags:callback:context:", streamEvents
, clientCB
, clientContext
);
1184 streamEvents
&= ~kCFStreamEventHasBytesAvailable
;
1185 return _CFStreamSetClient((struct _CFStream
*)writeStream
, streamEvents
, (void (*)(struct _CFStream
*, CFStreamEventType
, void *))clientCB
, clientContext
);
1188 CF_INLINE
void *_CFStreamGetClient(struct _CFStream
*stream
) {
1189 if (stream
->client
) return stream
->client
->cbContext
.info
;
1193 CF_EXPORT
void *_CFReadStreamGetClient(CFReadStreamRef readStream
) {
1194 return _CFStreamGetClient((struct _CFStream
*)readStream
);
1197 CF_EXPORT
void *_CFWriteStreamGetClient(CFWriteStreamRef writeStream
) {
1198 return _CFStreamGetClient((struct _CFStream
*)writeStream
);
1202 __private_extern__
void _CFStreamScheduleWithRunLoop(struct _CFStream
*stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1203 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1205 if (!stream
->client
) {
1206 _initializeClient(stream
);
1207 if (!stream
->client
) return; // we don't support asynch.
1210 if (!stream
->client
->rlSource
) {
1211 /* No source, so we join the shared source group */
1212 CFTypeRef a
[] = { runLoop
, runLoopMode
};
1214 CFArrayRef runLoopAndSourceKey
= CFArrayCreate(kCFAllocatorSystemDefault
, a
, sizeof(a
) / sizeof(a
[0]), &kCFTypeArrayCallBacks
);
1216 __CFSpinLock(&sSourceLock
);
1218 if (!sSharedSources
)
1219 sSharedSources
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1221 CFMutableArrayRef listOfStreamsSharingASource
= (CFMutableArrayRef
)CFDictionaryGetValue(sSharedSources
, runLoopAndSourceKey
);
1222 if (listOfStreamsSharingASource
) {
1223 stream
->client
->rlSource
= (CFRunLoopSourceRef
)CFRetain(((struct _CFStream
*)CFArrayGetValueAtIndex(listOfStreamsSharingASource
, 0))->client
->rlSource
);
1224 CFRetain(listOfStreamsSharingASource
);
1227 CFRunLoopSourceContext ctxt
= {
1232 (CFStringRef(*)(const void *))CFCopyDescription
,
1237 (void(*)(void *))_cfstream_shared_signalEventSync
1240 listOfStreamsSharingASource
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
1241 CFDictionaryAddValue(sSharedSources
, runLoopAndSourceKey
, listOfStreamsSharingASource
);
1243 ctxt
.info
= listOfStreamsSharingASource
;
1245 stream
->client
->rlSource
= CFRunLoopSourceCreate(kCFAllocatorSystemDefault
, 0, &ctxt
);
1247 CFRunLoopAddSource(runLoop
, stream
->client
->rlSource
, runLoopMode
);
1250 CFArrayAppendValue(listOfStreamsSharingASource
, stream
);
1251 CFDictionaryAddValue(sSharedSources
, stream
, runLoopAndSourceKey
);
1253 CFRelease(runLoopAndSourceKey
);
1254 CFRelease(listOfStreamsSharingASource
);
1256 __CFBitSet(stream
->flags
, SHARED_SOURCE
);
1258 __CFSpinUnlock(&sSourceLock
);
1260 else if (__CFBitIsSet(stream
->flags
, SHARED_SOURCE
)) {
1261 /* We were sharing, but now we'll get our own source */
1263 CFArrayRef runLoopAndSourceKey
;
1264 CFMutableArrayRef listOfStreamsSharingASource
;
1267 CFAllocatorRef alloc
= CFGetAllocator(stream
);
1268 CFRunLoopSourceContext ctxt
= {
1271 NULL
, // Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop
1272 NULL
, // Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop
1273 (CFStringRef(*)(const void *))CFCopyDescription
,
1278 (void(*)(void *))_cfstream_solo_signalEventSync
1281 __CFSpinLock(&sSourceLock
);
1283 runLoopAndSourceKey
= (CFArrayRef
)CFRetain((CFTypeRef
)CFDictionaryGetValue(sSharedSources
, stream
));
1284 listOfStreamsSharingASource
= (CFMutableArrayRef
)CFDictionaryGetValue(sSharedSources
, runLoopAndSourceKey
);
1286 c
= CFArrayGetCount(listOfStreamsSharingASource
);
1287 i
= CFArrayGetFirstIndexOfValue(listOfStreamsSharingASource
, CFRangeMake(0, c
), stream
);
1288 if (i
!= kCFNotFound
) {
1289 CFArrayRemoveValueAtIndex(listOfStreamsSharingASource
, i
);
1294 CFRunLoopRemoveSource((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoopAndSourceKey
, 0), stream
->client
->rlSource
, (CFStringRef
)CFArrayGetValueAtIndex(runLoopAndSourceKey
, 1));
1295 CFRunLoopSourceInvalidate(stream
->client
->rlSource
);
1296 CFDictionaryRemoveValue(sSharedSources
, runLoopAndSourceKey
);
1299 CFDictionaryRemoveValue(sSharedSources
, stream
);
1301 CFRelease(stream
->client
->rlSource
);
1302 __CFBitClear(stream
->flags
, SHARED_SOURCE
);
1304 __CFSpinUnlock(&sSourceLock
);
1306 stream
->client
->rlSource
= CFRunLoopSourceCreate(alloc
, 0, &ctxt
);
1308 CFRunLoopAddSource((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoopAndSourceKey
, 0), stream
->client
->rlSource
, (CFStringRef
)CFArrayGetValueAtIndex(runLoopAndSourceKey
, 1));
1310 CFRelease(runLoopAndSourceKey
);
1312 CFRunLoopAddSource(runLoop
, stream
->client
->rlSource
, runLoopMode
);
1314 /* We're not sharing, so just add the source to the rl & mode */
1315 CFRunLoopAddSource(runLoop
, stream
->client
->rlSource
, runLoopMode
);
1318 if (!stream
->client
->runLoopsAndModes
) {
1319 stream
->client
->runLoopsAndModes
= CFArrayCreateMutable(CFGetAllocator(stream
), 0, &kCFTypeArrayCallBacks
);
1321 CFArrayAppendValue(stream
->client
->runLoopsAndModes
, runLoop
);
1322 CFArrayAppendValue(stream
->client
->runLoopsAndModes
, runLoopMode
);
1325 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1326 cb
->schedule(stream
, runLoop
, runLoopMode
, _CFStreamGetInfoPointer(stream
));
1327 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1331 * If we've got events pending, we need to wake up and signal
1333 if (stream
->client
->whatToSignal
!= 0) {
1334 CFRunLoopSourceSignal(stream
->client
->rlSource
);
1335 _wakeUpRunLoop(stream
);
1339 CF_EXPORT
void CFReadStreamScheduleWithRunLoop(CFReadStreamRef stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1340 CF_OBJC_FUNCDISPATCH2(__kCFReadStreamTypeID
, void, stream
, "_scheduleInCFRunLoop:forMode:", runLoop
, runLoopMode
);
1341 _CFStreamScheduleWithRunLoop((struct _CFStream
*)stream
, runLoop
, runLoopMode
);
1344 CF_EXPORT
void CFWriteStreamScheduleWithRunLoop(CFWriteStreamRef stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1345 CF_OBJC_FUNCDISPATCH2(__kCFWriteStreamTypeID
, void, stream
, "_scheduleInCFRunLoop:forMode:", runLoop
, runLoopMode
);
1346 _CFStreamScheduleWithRunLoop((struct _CFStream
*)stream
, runLoop
, runLoopMode
);
1350 __private_extern__
void _CFStreamUnscheduleFromRunLoop(struct _CFStream
*stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1351 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1352 if (!stream
->client
) return;
1353 if (!stream
->client
->rlSource
) return;
1355 if (!__CFBitIsSet(stream
->flags
, SHARED_SOURCE
)) {
1356 CFRunLoopRemoveSource(runLoop
, stream
->client
->rlSource
, runLoopMode
);
1358 CFArrayRef runLoopAndSourceKey
;
1359 CFMutableArrayRef list
;
1362 __CFSpinLock(&sSourceLock
);
1364 runLoopAndSourceKey
= (CFArrayRef
)CFDictionaryGetValue(sSharedSources
, stream
);
1365 list
= (CFMutableArrayRef
)CFDictionaryGetValue(sSharedSources
, runLoopAndSourceKey
);
1367 c
= CFArrayGetCount(list
);
1368 i
= CFArrayGetFirstIndexOfValue(list
, CFRangeMake(0, c
), stream
);
1369 if (i
!= kCFNotFound
) {
1370 CFArrayRemoveValueAtIndex(list
, i
);
1375 CFRunLoopRemoveSource(runLoop
, stream
->client
->rlSource
, runLoopMode
);
1376 CFRunLoopSourceInvalidate(stream
->client
->rlSource
);
1377 CFDictionaryRemoveValue(sSharedSources
, runLoopAndSourceKey
);
1380 CFDictionaryRemoveValue(sSharedSources
, stream
);
1382 CFRelease(stream
->client
->rlSource
);
1383 stream
->client
->rlSource
= NULL
;
1384 __CFBitClear(stream
->flags
, SHARED_SOURCE
);
1386 __CFSpinUnlock(&sSourceLock
);
1389 _CFStreamRemoveRunLoopAndModeFromArray(stream
->client
->runLoopsAndModes
, runLoop
, runLoopMode
);
1391 if (cb
->unschedule
) {
1392 cb
->unschedule(stream
, runLoop
, runLoopMode
, _CFStreamGetInfoPointer(stream
));
1396 CF_EXPORT
void CFReadStreamUnscheduleFromRunLoop(CFReadStreamRef stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1397 CF_OBJC_FUNCDISPATCH2(__kCFReadStreamTypeID
, void, stream
, "_unscheduleFromCFRunLoop:forMode:", runLoop
, runLoopMode
);
1398 _CFStreamUnscheduleFromRunLoop((struct _CFStream
*)stream
, runLoop
, runLoopMode
);
1401 void CFWriteStreamUnscheduleFromRunLoop(CFWriteStreamRef stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1402 CF_OBJC_FUNCDISPATCH2(__kCFWriteStreamTypeID
, void, stream
, "_unscheduleFromCFRunLoop:forMode:", runLoop
, runLoopMode
);
1403 _CFStreamUnscheduleFromRunLoop((struct _CFStream
*)stream
, runLoop
, runLoopMode
);
1406 static void waitForOpen(struct _CFStream
*stream
) {
1407 CFRunLoopRef runLoop
= CFRunLoopGetCurrent();
1408 CFStringRef privateMode
= CFSTR("_kCFStreamBlockingOpenMode");
1409 _CFStreamScheduleWithRunLoop(stream
, runLoop
, privateMode
);
1410 // 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....
1411 while (__CFStreamGetStatus(stream
) == kCFStreamStatusOpening
) {
1412 CFRunLoopRunInMode(privateMode
, 1e+20, TRUE
);
1414 _CFStreamUnscheduleFromRunLoop(stream
, runLoop
, privateMode
);
1417 CF_INLINE CFArrayRef
_CFStreamGetRunLoopsAndModes(struct _CFStream
*stream
) {
1418 if (stream
->client
) return stream
->client
->runLoopsAndModes
;
1422 CF_EXPORT CFArrayRef
_CFReadStreamGetRunLoopsAndModes(CFReadStreamRef readStream
) {
1423 return _CFStreamGetRunLoopsAndModes((struct _CFStream
*)readStream
);
1426 CF_EXPORT CFArrayRef
_CFWriteStreamGetRunLoopsAndModes(CFWriteStreamRef writeStream
) {
1427 return _CFStreamGetRunLoopsAndModes((struct _CFStream
*)writeStream
);
1430 CF_EXPORT
void CFReadStreamSignalEvent(CFReadStreamRef stream
, CFStreamEventType event
, const void *error
) {
1431 _CFStreamSignalEvent((struct _CFStream
*)stream
, event
, (CFErrorRef
)error
, TRUE
);
1434 CF_EXPORT
void CFWriteStreamSignalEvent(CFWriteStreamRef stream
, CFStreamEventType event
, const void *error
) {
1435 _CFStreamSignalEvent((struct _CFStream
*)stream
, event
, (CFErrorRef
)error
, TRUE
);
1438 CF_EXPORT
void _CFReadStreamSignalEventDelayed(CFReadStreamRef stream
, CFStreamEventType event
, const void *error
) {
1439 _CFStreamSignalEvent((struct _CFStream
*)stream
, event
, (CFErrorRef
)error
, FALSE
);
1442 CF_EXPORT
void _CFReadStreamClearEvent(CFReadStreamRef readStream
, CFStreamEventType event
) {
1443 struct _CFStream
*stream
= (struct _CFStream
*)readStream
;
1444 if (stream
->client
) {
1445 stream
->client
->whatToSignal
&= ~event
;
1449 CF_EXPORT
void _CFWriteStreamSignalEventDelayed(CFWriteStreamRef stream
, CFStreamEventType event
, const void *error
) {
1450 _CFStreamSignalEvent((struct _CFStream
*)stream
, event
, (CFErrorRef
)error
, FALSE
);
1453 CF_EXPORT
void *CFReadStreamGetInfoPointer(CFReadStreamRef stream
) {
1454 return _CFStreamGetInfoPointer((struct _CFStream
*)stream
);
1457 CF_EXPORT
void *CFWriteStreamGetInfoPointer(CFWriteStreamRef stream
) {
1458 return _CFStreamGetInfoPointer((struct _CFStream
*)stream
);
1462 void _CFStreamSourceScheduleWithRunLoop(CFRunLoopSourceRef source
, CFMutableArrayRef runLoopsAndModes
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
)
1467 count
= CFArrayGetCount(runLoopsAndModes
);
1468 range
= CFRangeMake(0, count
);
1470 while (range
.length
) {
1472 CFIndex i
= CFArrayGetFirstIndexOfValue(runLoopsAndModes
, range
, runLoop
);
1474 if (i
== kCFNotFound
)
1477 if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes
, i
+ 1), runLoopMode
))
1480 range
.location
= i
+ 2;
1481 range
.length
= count
- range
.location
;
1484 // Add the new values.
1485 CFArrayAppendValue(runLoopsAndModes
, runLoop
);
1486 CFArrayAppendValue(runLoopsAndModes
, runLoopMode
);
1488 // Schedule the source on the new loop and mode.
1490 CFRunLoopAddSource(runLoop
, source
, runLoopMode
);
1495 void _CFStreamSourceUnscheduleFromRunLoop(CFRunLoopSourceRef source
, CFMutableArrayRef runLoopsAndModes
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
)
1500 count
= CFArrayGetCount(runLoopsAndModes
);
1501 range
= CFRangeMake(0, count
);
1503 while (range
.length
) {
1505 CFIndex i
= CFArrayGetFirstIndexOfValue(runLoopsAndModes
, range
, runLoop
);
1507 // If not found, it's not scheduled on it.
1508 if (i
== kCFNotFound
)
1511 // Make sure it is scheduled in this mode.
1512 if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes
, i
+ 1), runLoopMode
)) {
1514 // Remove mode and runloop from the list.
1515 CFArrayReplaceValues(runLoopsAndModes
, CFRangeMake(i
, 2), NULL
, 0);
1517 // Remove it from the runloop.
1519 CFRunLoopRemoveSource(runLoop
, source
, runLoopMode
);
1524 range
.location
= i
+ 2;
1525 range
.length
= count
- range
.location
;
1531 void _CFStreamSourceScheduleWithAllRunLoops(CFRunLoopSourceRef source
, CFArrayRef runLoopsAndModes
)
1533 CFIndex i
, count
= CFArrayGetCount(runLoopsAndModes
);
1538 for (i
= 0; i
< count
; i
+= 2) {
1540 // Make sure it's scheduled on all the right loops and modes.
1541 // Go through the array adding the source to all loops and modes.
1542 CFRunLoopAddSource((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoopsAndModes
, i
),
1544 (CFStringRef
)CFArrayGetValueAtIndex(runLoopsAndModes
, i
+ 1));
1550 void _CFStreamSourceUncheduleFromAllRunLoops(CFRunLoopSourceRef source
, CFArrayRef runLoopsAndModes
)
1552 CFIndex i
, count
= CFArrayGetCount(runLoopsAndModes
);
1557 for (i
= 0; i
< count
; i
+= 2) {
1559 // Go through the array removing the source from all loops and modes.
1560 CFRunLoopRemoveSource((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoopsAndModes
, i
),
1562 (CFStringRef
)CFArrayGetValueAtIndex(runLoopsAndModes
, i
+ 1));
1566 Boolean
_CFStreamRemoveRunLoopAndModeFromArray(CFMutableArrayRef runLoopsAndModes
, CFRunLoopRef rl
, CFStringRef mode
) {
1568 Boolean found
= FALSE
;
1570 if (!runLoopsAndModes
) return FALSE
;
1572 cnt
= CFArrayGetCount(runLoopsAndModes
);
1573 for (idx
= 0; idx
+ 1 < cnt
; idx
+= 2) {
1574 if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes
, idx
), rl
) && CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes
, idx
+ 1), mode
)) {
1575 CFArrayRemoveValueAtIndex(runLoopsAndModes
, idx
);
1576 CFArrayRemoveValueAtIndex(runLoopsAndModes
, idx
);
1584 // Used by NSStream to properly allocate the bridged objects
1585 CF_EXPORT CFIndex
_CFStreamInstanceSize(void) {
1586 return sizeof(struct _CFStream
);
1589 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1590 #elif DEPLOYMENT_TARGET_WINDOWS
1591 void __CFStreamCleanup(void) {
1592 __CFSpinLock(&sSourceLock
);
1593 if (sSharedSources
) {
1594 CFIndex count
= CFDictionaryGetCount(sSharedSources
);
1596 // Only release if empty. If it's still holding streams (which would be a client
1597 // bug leak), freeing this dict would free the streams, which then need to access the
1598 // dict to remove themselves, which leads to a deadlock.
1599 CFRelease(sSharedSources
);
1600 sSharedSources
= NULL
;
1602 const void ** keys
= (const void **)malloc(sizeof(const void *) * count
);
1606 CFDictionaryGetKeysAndValues(sSharedSources
, keys
, NULL
);
1607 fprintf(stderr
, "*** CFNetwork is shutting down, but %ld streams are still scheduled.\n", count
);
1609 for (i
= 0; i
< count
;i
++) {
1610 if ((CFGetTypeID(keys
[i
]) == __kCFReadStreamTypeID
) || (CFGetTypeID(keys
[i
]) == __kCFWriteStreamTypeID
)) {
1617 __CFSpinUnlock(&sSourceLock
);
1620 #error Unknown or unspecified DEPLOYMENT_TARGET