2 * Copyright (c) 2005 Apple Computer, 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 2000-2002, Apple, Inc. All rights reserved.
25 Responsibility: Becky Willrich
28 #include <CoreFoundation/CFRuntime.h>
31 #include "CFInternal.h"
32 #include "CFStreamPriv.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
= 0;
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 static void _CFStreamSignalEventSynch(void* info
);
72 __private_extern__ CFStreamStatus
_CFStreamGetStatus(struct _CFStream
*stream
);
73 static Boolean
_CFStreamRemoveRunLoopAndModeFromArray(CFMutableArrayRef runLoopsAndModes
, CFRunLoopRef rl
, CFStringRef mode
);
74 static void _wakeUpRunLoop(struct _CFStream
*stream
);
76 CF_INLINE
const struct _CFStreamCallBacks
*_CFStreamGetCallBackPtr(struct _CFStream
*stream
) {
77 return stream
->callBacks
;
80 CF_INLINE
void _CFStreamSetStatusCode(struct _CFStream
*stream
, CFStreamStatus newStatus
) {
81 CFStreamStatus status
= __CFStreamGetStatus(stream
);
82 if (((status
!= kCFStreamStatusClosed
) && (status
!= kCFStreamStatusError
)) ||
83 ((status
== kCFStreamStatusClosed
) && (newStatus
== kCFStreamStatusError
)))
85 __CFBitfieldSetValue(stream
->flags
, MAX_STATUS_CODE_BIT
, MIN_STATUS_CODE_BIT
, newStatus
);
89 CF_INLINE
void _CFStreamScheduleEvent(struct _CFStream
*stream
, CFStreamEventType event
) {
90 if (stream
->client
&& (stream
->client
->when
& event
) && stream
->client
->rlSource
) {
91 stream
->client
->whatToSignal
|= event
;
92 CFRunLoopSourceSignal(stream
->client
->rlSource
);
93 _wakeUpRunLoop(stream
);
98 static CFHashCode
__CFStreamHash(CFTypeRef cf
) {
99 return (((int)cf
) >> 5);
102 static CFStringRef
__CFStreamCopyDescription(CFTypeRef cf
) {
103 struct _CFStream
*stream
= (struct _CFStream
*)cf
;
104 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
105 CFStringRef contextDescription
;
107 if (cb
->copyDescription
) {
108 if (cb
->version
== 0) {
109 contextDescription
= ((CFStringRef(*)(void *))cb
->copyDescription
)(_CFStreamGetInfoPointer(stream
));
111 contextDescription
= cb
->copyDescription(stream
, _CFStreamGetInfoPointer(stream
));
114 contextDescription
= CFStringCreateWithFormat(CFGetAllocator(stream
), NULL
, CFSTR("info = 0x%lx"), (UInt32
)((const void*)_CFStreamGetInfoPointer(stream
)));
116 if (CFGetTypeID(cf
) == __kCFReadStreamTypeID
) {
117 desc
= CFStringCreateWithFormat(CFGetAllocator(stream
), NULL
, CFSTR("<CFReadStream 0x%x>{%@}"), (UInt32
)stream
, contextDescription
);
119 desc
= CFStringCreateWithFormat(CFGetAllocator(stream
), NULL
, CFSTR("<CFWriteStream 0x%x>{%@}"), (UInt32
)stream
, contextDescription
);
121 CFRelease(contextDescription
);
125 __private_extern__
void _CFStreamClose(struct _CFStream
*stream
) {
126 CFStreamStatus status
= _CFStreamGetStatus(stream
);
127 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
128 if (status
== kCFStreamStatusNotOpen
|| status
== kCFStreamStatusClosed
|| (status
== kCFStreamStatusError
&& __CFBitIsSet(stream
->flags
, HAVE_CLOSED
))) {
129 // Stream is not open
132 __CFBitSet(stream
->flags
, HAVE_CLOSED
);
133 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
135 cb
->close(stream
, _CFStreamGetInfoPointer(stream
));
137 if (stream
->client
&& stream
->client
->rlSource
) {
139 if (!__CFBitIsSet(stream
->flags
, SHARED_SOURCE
)) {
140 CFRunLoopSourceInvalidate(stream
->client
->rlSource
);
141 CFRelease(stream
->client
->rlSource
);
142 stream
->client
->rlSource
= NULL
;
147 CFMutableArrayRef list
;
150 __CFSpinLock(&sSourceLock
);
152 key
= (CFArrayRef
)CFDictionaryGetValue(sSharedSources
, stream
);
153 list
= (CFMutableArrayRef
)CFDictionaryGetValue(sSharedSources
, key
);
155 c
= CFArrayGetCount(list
);
156 i
= CFArrayGetFirstIndexOfValue(list
, CFRangeMake(0, c
), stream
);
157 if (i
!= kCFNotFound
) {
158 CFArrayRemoveValueAtIndex(list
, i
);
163 CFRunLoopRemoveSource((CFRunLoopRef
)CFArrayGetValueAtIndex(key
, 0), stream
->client
->rlSource
, (CFStringRef
)CFArrayGetValueAtIndex(key
, 1));
164 CFRunLoopSourceInvalidate(stream
->client
->rlSource
);
165 CFDictionaryRemoveValue(sSharedSources
, key
);
168 CFDictionaryRemoveValue(sSharedSources
, stream
);
170 CFRelease(stream
->client
->rlSource
);
171 stream
->client
->rlSource
= NULL
;
172 __CFBitClear(stream
->flags
, SHARED_SOURCE
);
174 __CFSpinUnlock(&sSourceLock
);
177 _CFStreamSetStatusCode(stream
, kCFStreamStatusClosed
);
178 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
181 //static int numStreamInstances = 0;
183 static void __CFStreamDeallocate(CFTypeRef cf
) {
184 struct _CFStream
*stream
= (struct _CFStream
*)cf
;
185 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
186 CFStreamStatus status
= _CFStreamGetStatus(stream
);
187 CFAllocatorRef alloc
= CFGetAllocator(stream
);
188 // numStreamInstances --;
189 if ((status
!= kCFStreamStatusError
|| __CFBitIsSet(stream
->flags
, HAVE_CLOSED
)) && status
!= kCFStreamStatusClosed
&& status
!= kCFStreamStatusNotOpen
) {
191 _CFStreamClose(stream
);
193 if (stream
->client
) {
194 CFStreamClientContext
*cbContext
;
195 cbContext
= &(stream
->client
->cbContext
);
196 if (cbContext
->info
&& cbContext
->release
) {
197 cbContext
->release(cbContext
->info
);
199 if (stream
->client
->rlSource
) {
200 if (!__CFBitIsSet(stream
->flags
, SHARED_SOURCE
)) {
201 CFRunLoopSourceInvalidate(stream
->client
->rlSource
);
202 CFRelease(stream
->client
->rlSource
);
203 stream
->client
->rlSource
= NULL
;
208 CFMutableArrayRef list
;
211 __CFSpinLock(&sSourceLock
);
213 key
= (CFArrayRef
)CFDictionaryGetValue(sSharedSources
, stream
);
214 list
= (CFMutableArrayRef
)CFDictionaryGetValue(sSharedSources
, key
);
216 c
= CFArrayGetCount(list
);
217 i
= CFArrayGetFirstIndexOfValue(list
, CFRangeMake(0, c
), stream
);
218 if (i
!= kCFNotFound
) {
219 CFArrayRemoveValueAtIndex(list
, i
);
224 CFRunLoopRemoveSource((CFRunLoopRef
)CFArrayGetValueAtIndex(key
, 0), stream
->client
->rlSource
, (CFStringRef
)CFArrayGetValueAtIndex(key
, 1));
225 CFRunLoopSourceInvalidate(stream
->client
->rlSource
);
226 CFDictionaryRemoveValue(sSharedSources
, key
);
229 CFDictionaryRemoveValue(sSharedSources
, stream
);
231 CFRelease(stream
->client
->rlSource
);
232 stream
->client
->rlSource
= NULL
;
233 __CFBitClear(stream
->flags
, SHARED_SOURCE
);
235 __CFSpinUnlock(&sSourceLock
);
238 if (stream
->client
->runLoopsAndModes
) {
239 CFRelease(stream
->client
->runLoopsAndModes
);
242 CFAllocatorDeallocate(alloc
, stream
->client
);
243 stream
->client
= NULL
; // Just in case finalize, below, calls back in to us
246 if (cb
->version
== 0) {
247 ((void(*)(void *))cb
->finalize
)(_CFStreamGetInfoPointer(stream
));
249 cb
->finalize(stream
, _CFStreamGetInfoPointer(stream
));
252 if (!__CFBitIsSet(stream
->flags
, CONSTANT_CALLBACKS
)) {
253 CFAllocatorDeallocate(alloc
, (void *)stream
->callBacks
);
257 static const CFRuntimeClass __CFReadStreamClass
= {
262 __CFStreamDeallocate
,
265 NULL
, // copyHumanDesc
266 __CFStreamCopyDescription
269 static const CFRuntimeClass __CFWriteStreamClass
= {
274 __CFStreamDeallocate
,
277 NULL
, // copyHumanDesc
278 __CFStreamCopyDescription
281 CONST_STRING_DECL(kCFStreamPropertySocketNativeHandle
, "kCFStreamPropertySocketNativeHandle")
282 CONST_STRING_DECL(kCFStreamPropertySocketRemoteHostName
, "kCFStreamPropertySocketRemoteHostName")
283 CONST_STRING_DECL(kCFStreamPropertySocketRemotePortNumber
, "kCFStreamPropertySocketRemotePortNumber")
284 CONST_STRING_DECL(kCFStreamPropertyDataWritten
, "kCFStreamPropertyDataWritten")
285 CONST_STRING_DECL(kCFStreamPropertyAppendToFile
, "kCFStreamPropertyAppendToFile")
287 __private_extern__
void __CFStreamInitialize(void) {
288 __kCFReadStreamTypeID
= _CFRuntimeRegisterClass(&__CFReadStreamClass
);
289 __kCFWriteStreamTypeID
= _CFRuntimeRegisterClass(&__CFWriteStreamClass
);
293 CF_EXPORT CFTypeID
CFReadStreamGetTypeID(void) {
294 return __kCFReadStreamTypeID
;
297 CF_EXPORT CFTypeID
CFWriteStreamGetTypeID(void) {
298 return __kCFWriteStreamTypeID
;
301 static struct _CFStream
*_CFStreamCreate(CFAllocatorRef allocator
, Boolean isReadStream
) {
302 struct _CFStream
*newStream
= (struct _CFStream
*)_CFRuntimeCreateInstance(allocator
, isReadStream
? __kCFReadStreamTypeID
: __kCFWriteStreamTypeID
, sizeof(struct _CFStream
) - sizeof(CFRuntimeBase
), NULL
);
304 // numStreamInstances ++;
305 newStream
->flags
= 0;
306 _CFStreamSetStatusCode(newStream
, kCFStreamStatusNotOpen
);
307 newStream
->error
.domain
= 0;
308 newStream
->error
.error
= 0;
309 newStream
->client
= NULL
;
310 newStream
->info
= NULL
;
311 newStream
->callBacks
= NULL
;
316 __private_extern__
struct _CFStream
*_CFStreamCreateWithConstantCallbacks(CFAllocatorRef alloc
, void *info
, const struct _CFStreamCallBacks
*cb
, Boolean isReading
) {
317 struct _CFStream
*newStream
;
318 if (cb
->version
!= 1) return NULL
;
319 newStream
= _CFStreamCreate(alloc
, isReading
);
321 __CFBitSet(newStream
->flags
, CONSTANT_CALLBACKS
);
322 newStream
->callBacks
= cb
;
324 newStream
->info
= cb
->create(newStream
, info
);
326 newStream
->info
= info
;
332 CF_EXPORT
void _CFStreamSetInfoPointer(struct _CFStream
*stream
, void *info
, const struct _CFStreamCallBacks
*cb
) {
333 if (info
!= stream
->info
) {
334 if (stream
->callBacks
->finalize
) {
335 stream
->callBacks
->finalize(stream
, stream
->info
);
338 stream
->info
= cb
->create(stream
, info
);
343 stream
->callBacks
= cb
;
347 CF_EXPORT CFReadStreamRef
CFReadStreamCreate(CFAllocatorRef alloc
, const CFReadStreamCallBacks
*callbacks
, void *info
) {
348 struct _CFStream
*newStream
= _CFStreamCreate(alloc
, TRUE
);
349 struct _CFStreamCallBacks
*cb
;
350 if (!newStream
) return NULL
;
351 cb
= CFAllocatorAllocate(alloc
, sizeof(struct _CFStreamCallBacks
), 0);
353 CFRelease(newStream
);
356 if (callbacks
->version
== 0) {
357 CFReadStreamCallBacksV0
*cbV0
= (CFReadStreamCallBacksV0
*)callbacks
;
358 CFStreamClientContext
*ctxt
= (CFStreamClientContext
*)info
;
359 newStream
->info
= ctxt
->retain
? (void *)ctxt
->retain(ctxt
->info
) : ctxt
->info
;
361 cb
->create
= (void *(*)(struct _CFStream
*, void *))ctxt
->retain
;
362 cb
->finalize
= (void(*)(struct _CFStream
*, void *))ctxt
->release
;
363 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))ctxt
->copyDescription
;
364 cb
->open
= (Boolean(*)(struct _CFStream
*, CFStreamError
*, Boolean
*, void *))cbV0
->open
;
365 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFStreamError
*, void *))cbV0
->openCompleted
;
366 cb
->read
= cbV0
->read
;
367 cb
->getBuffer
= cbV0
->getBuffer
;
368 cb
->canRead
= cbV0
->canRead
;
371 cb
->close
= (void (*)(struct _CFStream
*, void *))cbV0
->close
;
372 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))cbV0
->copyProperty
;
373 cb
->setProperty
= NULL
;
374 cb
->requestEvents
= NULL
;
375 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV0
->schedule
;
376 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV0
->unschedule
;
378 newStream
->info
= callbacks
->create
? callbacks
->create((CFReadStreamRef
)newStream
, info
) : info
;
380 cb
->create
= (void *(*)(struct _CFStream
*, void *))callbacks
->create
;
381 cb
->finalize
= (void(*)(struct _CFStream
*, void *))callbacks
->finalize
;
382 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))callbacks
->copyDescription
;
383 cb
->open
= (Boolean(*)(struct _CFStream
*, CFStreamError
*, Boolean
*, void *))callbacks
->open
;
384 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFStreamError
*, void *))callbacks
->openCompleted
;
385 cb
->read
= callbacks
->read
;
386 cb
->getBuffer
= callbacks
->getBuffer
;
387 cb
->canRead
= callbacks
->canRead
;
390 cb
->close
= (void (*)(struct _CFStream
*, void *))callbacks
->close
;
391 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))callbacks
->copyProperty
;
392 cb
->setProperty
= (Boolean(*)(struct _CFStream
*, CFStringRef
, CFTypeRef
, void *))callbacks
->setProperty
;
393 cb
->requestEvents
= (void(*)(struct _CFStream
*, CFOptionFlags
, void *))callbacks
->requestEvents
;
394 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))callbacks
->schedule
;
395 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))callbacks
->unschedule
;
397 newStream
->callBacks
= cb
;
398 return (CFReadStreamRef
)newStream
;
401 CF_EXPORT CFWriteStreamRef
CFWriteStreamCreate(CFAllocatorRef alloc
, const CFWriteStreamCallBacks
*callbacks
, void *info
) {
402 struct _CFStream
*newStream
= _CFStreamCreate(alloc
, FALSE
);
403 struct _CFStreamCallBacks
*cb
;
404 if (!newStream
) return NULL
;
405 cb
= CFAllocatorAllocate(alloc
, sizeof(struct _CFStreamCallBacks
), 0);
407 CFRelease(newStream
);
410 if (callbacks
->version
== 0) {
411 CFWriteStreamCallBacksV0
*cbV0
= (CFWriteStreamCallBacksV0
*)callbacks
;
412 CFStreamClientContext
*ctxt
= (CFStreamClientContext
*)info
;
413 newStream
->info
= ctxt
->retain
? (void *)ctxt
->retain(ctxt
->info
) : ctxt
->info
;
415 cb
->create
= (void *(*)(struct _CFStream
*, void *))ctxt
->retain
;
416 cb
->finalize
= (void(*)(struct _CFStream
*, void *))ctxt
->release
;
417 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))ctxt
->copyDescription
;
418 cb
->open
= (Boolean(*)(struct _CFStream
*, CFStreamError
*, Boolean
*, void *))cbV0
->open
;
419 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFStreamError
*, void *))cbV0
->openCompleted
;
421 cb
->getBuffer
= NULL
;
423 cb
->write
= cbV0
->write
;
424 cb
->canWrite
= cbV0
->canWrite
;
425 cb
->close
= (void (*)(struct _CFStream
*, void *))cbV0
->close
;
426 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))cbV0
->copyProperty
;
427 cb
->setProperty
= NULL
;
428 cb
->requestEvents
= NULL
;
429 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV0
->schedule
;
430 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV0
->unschedule
;
432 cb
->version
= callbacks
->version
;
433 newStream
->info
= callbacks
->create
? callbacks
->create((CFWriteStreamRef
)newStream
, info
) : info
;
434 cb
->create
= (void *(*)(struct _CFStream
*, void *))callbacks
->create
;
435 cb
->finalize
= (void(*)(struct _CFStream
*, void *))callbacks
->finalize
;
436 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))callbacks
->copyDescription
;
437 cb
->open
= (Boolean(*)(struct _CFStream
*, CFStreamError
*, Boolean
*, void *))callbacks
->open
;
438 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFStreamError
*, void *))callbacks
->openCompleted
;
440 cb
->getBuffer
= NULL
;
442 cb
->write
= callbacks
->write
;
443 cb
->canWrite
= callbacks
->canWrite
;
444 cb
->close
= (void (*)(struct _CFStream
*, void *))callbacks
->close
;
445 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))callbacks
->copyProperty
;
446 cb
->setProperty
= (Boolean (*)(struct _CFStream
*, CFStringRef
, CFTypeRef
, void *))callbacks
->setProperty
;
447 cb
->requestEvents
= (void(*)(struct _CFStream
*, CFOptionFlags
, void *))callbacks
->requestEvents
;
448 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))callbacks
->schedule
;
449 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))callbacks
->unschedule
;
451 newStream
->callBacks
= cb
;
452 return (CFWriteStreamRef
)newStream
;
455 static void _CFStreamSignalEventSynch(void* info
) {
457 struct _CFStream
*stream
= NULL
;
458 CFOptionFlags eventMask
, whatToSignal
= 0;
460 if (CFGetTypeID((CFTypeRef
)info
) != CFArrayGetTypeID()) {
461 stream
= (struct _CFStream
*)info
;
462 whatToSignal
= stream
->client
->whatToSignal
;
463 stream
->client
->whatToSignal
= 0;
467 CFMutableArrayRef list
= (CFMutableArrayRef
)info
;
470 __CFSpinLock(&sSourceLock
);
472 c
= CFArrayGetCount(list
);
473 for (i
= 0; i
< c
; i
++) {
474 struct _CFStream
* s
= (struct _CFStream
*)CFArrayGetValueAtIndex(list
, i
);
475 if (s
->client
->whatToSignal
) {
477 whatToSignal
= stream
->client
->whatToSignal
;
478 s
->client
->whatToSignal
= 0;
484 struct _CFStream
* s
= (struct _CFStream
*)CFArrayGetValueAtIndex(list
, i
);
485 if (s
->client
->whatToSignal
) {
486 CFRunLoopSourceSignal(s
->client
->rlSource
);
492 __CFSpinUnlock(&sSourceLock
);
498 CFRetain(stream
); // In case the client releases the stream while we're still in the for loop....
500 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
502 for (eventMask
= 1; eventMask
<= whatToSignal
; eventMask
= eventMask
<< 1) {
503 if ((eventMask
& whatToSignal
) && (stream
->client
->when
& eventMask
)) {
504 stream
->client
->cb(stream
, eventMask
, stream
->client
->cbContext
.info
);
508 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
513 // 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
514 // are likely to signal the same run loop over and over again. Don't know if we should worry about that.
515 static void _wakeUpRunLoop(struct _CFStream
*stream
) {
516 CFRunLoopRef rl
= NULL
;
519 if (!stream
->client
|| !stream
->client
->runLoopsAndModes
) return;
520 rlArray
= stream
->client
->runLoopsAndModes
;
521 cnt
= CFArrayGetCount(rlArray
);
522 if (cnt
== 0) return;
524 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, 0);
526 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, 0);
527 for (idx
= 2; NULL
!= rl
&& idx
< cnt
; idx
+=2) {
528 CFRunLoopRef value
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, idx
);
529 if (value
!= rl
) rl
= NULL
;
531 if (NULL
== rl
) { /* more than one different rl, so we must pick one */
532 for (idx
= 0; idx
< cnt
; idx
+=2) {
533 CFRunLoopRef value
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, idx
);
534 CFStringRef currentMode
= CFRunLoopCopyCurrentMode(value
);
535 if (NULL
!= currentMode
&& CFEqual(currentMode
, CFArrayGetValueAtIndex(rlArray
, idx
+1)) && CFRunLoopIsWaiting(value
)) {
536 CFRelease(currentMode
);
540 if (NULL
!= currentMode
) CFRelease(currentMode
);
542 if (NULL
== rl
) { /* didn't choose one above, so choose first */
543 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, 0);
547 if (NULL
!= rl
&& CFRunLoopIsWaiting(rl
)) CFRunLoopWakeUp(rl
);
550 __private_extern__
void _CFStreamSignalEvent(struct _CFStream
*stream
, CFStreamEventType event
, CFStreamError
*error
, Boolean synchronousAllowed
) {
551 // Update our internal status; we must use the primitive __CFStreamGetStatus(), because CFStreamGetStatus() calls us, and we can end up in an infinite loop.
552 CFStreamStatus status
= __CFStreamGetStatus(stream
);
553 // Sanity check the event
554 if (status
== kCFStreamStatusNotOpen
) {
555 // No events allowed; this is almost certainly a bug in the stream's implementation
556 CFLog(__kCFLogAssertion
, CFSTR("Stream 0x%x is sending an event before being opened"), stream
);
558 } else if (status
== kCFStreamStatusClosed
|| status
== kCFStreamStatusError
) {
559 // no further events are allowed
561 } else if (status
== kCFStreamStatusAtEnd
) {
562 // Only error events are allowed
563 event
&= kCFStreamEventErrorOccurred
;
564 } else if (status
!= kCFStreamStatusOpening
) {
565 // cannot send open completed; that happened already
566 event
&= ~kCFStreamEventOpenCompleted
;
569 // Change status if appropriate
570 if (event
& kCFStreamEventOpenCompleted
&& status
== kCFStreamStatusOpening
) {
571 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
573 if (event
& kCFStreamEventEndEncountered
&& status
< kCFStreamStatusAtEnd
) {
574 _CFStreamSetStatusCode(stream
, kCFStreamStatusAtEnd
);
576 if (event
& kCFStreamEventErrorOccurred
) {
577 stream
->error
.domain
= error
->domain
;
578 stream
->error
.error
= error
->error
;
579 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
582 // Now signal any pertinent event
583 if (stream
->client
&& stream
->client
->rlSource
&& (stream
->client
->when
& event
)) {
585 Boolean signalNow
= FALSE
;
587 stream
->client
->whatToSignal
|= event
;
589 if (synchronousAllowed
&& !__CFBitIsSet(stream
->flags
, CALLING_CLIENT
)) {
591 CFRunLoopRef rl
= CFRunLoopGetCurrent();
592 CFStringRef mode
= CFRunLoopCopyCurrentMode(rl
);
595 if (CFRunLoopContainsSource(rl
, stream
->client
->rlSource
, mode
))
602 // Can call out safely right now
603 _CFStreamSignalEventSynch(stream
);
605 // Schedule for later delivery
606 CFRunLoopSourceSignal(stream
->client
->rlSource
);
607 _wakeUpRunLoop(stream
);
612 __private_extern__ CFStreamStatus
_CFStreamGetStatus(struct _CFStream
*stream
) {
613 CFStreamStatus status
= __CFStreamGetStatus(stream
);
614 // 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.
615 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
616 if (status
== kCFStreamStatusOpening
) {
617 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
618 if (cb
->openCompleted
&& cb
->openCompleted(stream
, &(stream
->error
), _CFStreamGetInfoPointer(stream
))) {
619 if (stream
->error
.error
== 0) {
620 status
= kCFStreamStatusOpen
;
622 status
= kCFStreamStatusError
;
624 _CFStreamSetStatusCode(stream
, status
);
625 if (status
== kCFStreamStatusOpen
) {
626 _CFStreamScheduleEvent(stream
, kCFStreamEventOpenCompleted
);
628 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
632 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
636 CF_EXPORT CFStreamStatus
CFReadStreamGetStatus(CFReadStreamRef stream
) {
637 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID
, CFStreamStatus
, stream
, "streamStatus");
638 return _CFStreamGetStatus((struct _CFStream
*)stream
);
641 CF_EXPORT CFStreamStatus
CFWriteStreamGetStatus(CFWriteStreamRef stream
) {
642 CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID
, CFStreamStatus
, stream
, "streamStatus");
643 return _CFStreamGetStatus((struct _CFStream
*)stream
);
646 CF_EXPORT CFStreamError
CFReadStreamGetError(CFReadStreamRef stream
) {
647 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID
, CFStreamError
, stream
, "_cfStreamError");
648 return ((struct _CFStream
*)stream
)->error
;
651 CF_EXPORT CFStreamError
CFWriteStreamGetError(CFWriteStreamRef stream
) {
652 CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID
, CFStreamError
, stream
, "_cfStreamError");
653 return ((struct _CFStream
*)stream
)->error
;
656 __private_extern__ Boolean
_CFStreamOpen(struct _CFStream
*stream
) {
657 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
658 Boolean success
, openComplete
;
659 if (_CFStreamGetStatus(stream
) != kCFStreamStatusNotOpen
) {
662 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
663 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpening
);
665 success
= cb
->open(stream
, &(stream
->error
), &openComplete
, _CFStreamGetInfoPointer(stream
));
672 // 2957690 - Guard against the possibility that the stream has already signalled itself in to a later state (like AtEnd)
673 if (__CFStreamGetStatus(stream
) == kCFStreamStatusOpening
) {
674 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
676 _CFStreamScheduleEvent(stream
, kCFStreamEventOpenCompleted
);
678 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
679 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
680 __CFBitSet(stream
->flags
, HAVE_CLOSED
);
683 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
687 CF_EXPORT Boolean
CFReadStreamOpen(CFReadStreamRef stream
) {
688 if(CF_IS_OBJC(__kCFReadStreamTypeID
, stream
)) {
689 CF_OBJC_VOIDCALL0(stream
, "open");
692 return _CFStreamOpen((struct _CFStream
*)stream
);
695 CF_EXPORT Boolean
CFWriteStreamOpen(CFWriteStreamRef stream
) {
696 if(CF_IS_OBJC(__kCFWriteStreamTypeID
, stream
)) {
697 CF_OBJC_VOIDCALL0(stream
, "open");
700 return _CFStreamOpen((struct _CFStream
*)stream
);
703 CF_EXPORT
void CFReadStreamClose(CFReadStreamRef stream
) {
704 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID
, void, stream
, "close");
705 _CFStreamClose((struct _CFStream
*)stream
);
708 CF_EXPORT
void CFWriteStreamClose(CFWriteStreamRef stream
) {
709 CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID
, void, stream
, "close");
710 _CFStreamClose((struct _CFStream
*)stream
);
713 CF_EXPORT Boolean
CFReadStreamHasBytesAvailable(CFReadStreamRef readStream
) {
714 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID
, Boolean
, readStream
, "hasBytesAvailable");
715 struct _CFStream
*stream
= (struct _CFStream
*)readStream
;
716 CFStreamStatus status
= _CFStreamGetStatus(stream
);
717 const struct _CFStreamCallBacks
*cb
;
718 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusReading
) {
721 cb
= _CFStreamGetCallBackPtr(stream
);
722 if (cb
->canRead
== NULL
) {
723 return TRUE
; // No way to know without trying....
726 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
727 result
= cb
->canRead((CFReadStreamRef
)stream
, _CFStreamGetInfoPointer(stream
));
728 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
733 static void waitForOpen(struct _CFStream
*stream
);
734 CFIndex
CFReadStreamRead(CFReadStreamRef readStream
, UInt8
*buffer
, CFIndex bufferLength
) {
735 CF_OBJC_FUNCDISPATCH2(__kCFReadStreamTypeID
, CFIndex
, readStream
, "read:maxLength:", buffer
, bufferLength
);
736 struct _CFStream
*stream
= (struct _CFStream
*)readStream
;
737 CFStreamStatus status
= _CFStreamGetStatus(stream
);
738 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
739 if (status
== kCFStreamStatusOpening
) {
740 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
742 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
743 status
= _CFStreamGetStatus(stream
);
746 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusReading
&& status
!= kCFStreamStatusAtEnd
) {
748 } else if (status
== kCFStreamStatusAtEnd
) {
753 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
754 if (stream
->client
) {
755 stream
->client
->whatToSignal
&= ~kCFStreamEventHasBytesAvailable
;
757 _CFStreamSetStatusCode(stream
, kCFStreamStatusReading
);
758 bytesRead
= cb
->read((CFReadStreamRef
)stream
, buffer
, bufferLength
, &(stream
->error
), &atEOF
, _CFStreamGetInfoPointer(stream
));
759 if (stream
->error
.error
!= 0) {
761 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
762 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
764 _CFStreamSetStatusCode(stream
, kCFStreamStatusAtEnd
);
765 _CFStreamScheduleEvent(stream
, kCFStreamEventEndEncountered
);
767 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
769 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
774 CF_EXPORT
const UInt8
*CFReadStreamGetBuffer(CFReadStreamRef readStream
, CFIndex maxBytesToRead
, CFIndex
*numBytesRead
) {
775 if (CF_IS_OBJC(__kCFReadStreamTypeID
, readStream
)) {
776 uint8_t *bufPtr
= NULL
;
778 CF_OBJC_CALL2(Boolean
, gotBytes
, readStream
, "getBuffer:length:", &bufPtr
, numBytesRead
);
780 return (const UInt8
*)bufPtr
;
785 struct _CFStream
*stream
= (struct _CFStream
*)readStream
;
786 CFStreamStatus status
= _CFStreamGetStatus(stream
);
787 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
789 if (status
== kCFStreamStatusOpening
) {
790 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
792 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
793 status
= _CFStreamGetStatus(stream
);
795 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusReading
&& status
!= kCFStreamStatusAtEnd
) {
798 } else if (status
== kCFStreamStatusAtEnd
|| cb
->getBuffer
== NULL
) {
803 Boolean hadBytes
= stream
->client
&& (stream
->client
->whatToSignal
& kCFStreamEventHasBytesAvailable
);
804 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
806 stream
->client
->whatToSignal
&= ~kCFStreamEventHasBytesAvailable
;
808 _CFStreamSetStatusCode(stream
, kCFStreamStatusReading
);
809 buffer
= cb
->getBuffer((CFReadStreamRef
)stream
, maxBytesToRead
, numBytesRead
, &(stream
->error
), &atEOF
, _CFStreamGetInfoPointer(stream
));
810 if (stream
->error
.error
!= 0) {
812 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
814 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
816 _CFStreamSetStatusCode(stream
, kCFStreamStatusAtEnd
);
817 _CFStreamScheduleEvent(stream
, kCFStreamEventEndEncountered
);
819 if (!buffer
&& hadBytes
) {
820 stream
->client
->whatToSignal
|= kCFStreamEventHasBytesAvailable
;
822 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
824 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
829 CF_EXPORT Boolean
CFWriteStreamCanAcceptBytes(CFWriteStreamRef writeStream
) {
830 CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID
, Boolean
, writeStream
, "hasSpaceAvailable");
831 struct _CFStream
*stream
= (struct _CFStream
*)writeStream
;
832 CFStreamStatus status
= _CFStreamGetStatus(stream
);
833 const struct _CFStreamCallBacks
*cb
;
834 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusWriting
) {
837 cb
= _CFStreamGetCallBackPtr(stream
);
838 if (cb
->canWrite
== NULL
) {
839 return TRUE
; // No way to know without trying....
842 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
843 result
= cb
->canWrite((CFWriteStreamRef
)stream
, _CFStreamGetInfoPointer(stream
));
844 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
849 CF_EXPORT CFIndex
CFWriteStreamWrite(CFWriteStreamRef writeStream
, const UInt8
*buffer
, CFIndex bufferLength
) {
850 CF_OBJC_FUNCDISPATCH2(__kCFWriteStreamTypeID
, CFIndex
, writeStream
, "write:maxLength:", buffer
, bufferLength
);
851 struct _CFStream
*stream
= (struct _CFStream
*)writeStream
;
852 CFStreamStatus status
= _CFStreamGetStatus(stream
);
853 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
854 if (status
== kCFStreamStatusOpening
) {
855 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
857 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
858 status
= _CFStreamGetStatus(stream
);
860 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusWriting
) {
864 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
865 _CFStreamSetStatusCode(stream
, kCFStreamStatusWriting
);
866 if (stream
->client
) {
867 stream
->client
->whatToSignal
&= ~kCFStreamEventCanAcceptBytes
;
869 result
= cb
->write((CFWriteStreamRef
)stream
, buffer
, bufferLength
, &(stream
->error
), _CFStreamGetInfoPointer(stream
));
870 if (stream
->error
.error
!= 0) {
871 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
872 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
873 } else if (result
== 0) {
874 _CFStreamSetStatusCode(stream
, kCFStreamStatusAtEnd
);
875 _CFStreamScheduleEvent(stream
, kCFStreamEventEndEncountered
);
877 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
879 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
884 __private_extern__ CFTypeRef
_CFStreamCopyProperty(struct _CFStream
*stream
, CFStringRef propertyName
) {
885 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
886 if (cb
->copyProperty
== NULL
) {
890 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
891 result
= cb
->copyProperty(stream
, propertyName
, _CFStreamGetInfoPointer(stream
));
892 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
897 CF_EXPORT CFTypeRef
CFReadStreamCopyProperty(CFReadStreamRef stream
, CFStringRef propertyName
) {
898 CF_OBJC_FUNCDISPATCH1(__kCFReadStreamTypeID
, CFTypeRef
, stream
, "propertyForKey:", propertyName
);
899 return _CFStreamCopyProperty((struct _CFStream
*)stream
, propertyName
);
902 CF_EXPORT CFTypeRef
CFWriteStreamCopyProperty(CFWriteStreamRef stream
, CFStringRef propertyName
) {
903 CF_OBJC_FUNCDISPATCH1(__kCFWriteStreamTypeID
, CFTypeRef
, stream
, "propertyForKey:", propertyName
);
904 return _CFStreamCopyProperty((struct _CFStream
*)stream
, propertyName
);
907 __private_extern__ Boolean
_CFStreamSetProperty(struct _CFStream
*stream
, CFStringRef prop
, CFTypeRef val
) {
908 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
909 if (cb
->setProperty
== NULL
) {
913 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
914 result
= cb
->setProperty(stream
, prop
, val
, _CFStreamGetInfoPointer(stream
));
915 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
921 Boolean
CFReadStreamSetProperty(CFReadStreamRef stream
, CFStringRef propertyName
, CFTypeRef propertyValue
) {
922 CF_OBJC_FUNCDISPATCH2(__kCFReadStreamTypeID
, Boolean
, stream
, "setProperty:forKey:", propertyValue
, propertyName
);
923 return _CFStreamSetProperty((struct _CFStream
*)stream
, propertyName
, propertyValue
);
927 Boolean
CFWriteStreamSetProperty(CFWriteStreamRef stream
, CFStringRef propertyName
, CFTypeRef propertyValue
) {
928 CF_OBJC_FUNCDISPATCH2(__kCFWriteStreamTypeID
, Boolean
, stream
, "setProperty:forKey:", propertyValue
, propertyName
);
929 return _CFStreamSetProperty((struct _CFStream
*)stream
, propertyName
, propertyValue
);
932 static void _initializeClient(struct _CFStream
*stream
) {
933 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
934 if (!cb
->schedule
) return; // Do we wish to allow this?
935 stream
->client
= CFAllocatorAllocate(CFGetAllocator(stream
), sizeof(struct _CFStreamClient
), 0);
936 memset(stream
->client
, 0, sizeof(struct _CFStreamClient
));
939 /* If we add a setClient callback to the concrete stream callbacks, we must set/clear CALLING_CLIENT around it */
940 __private_extern__ Boolean
_CFStreamSetClient(struct _CFStream
*stream
, CFOptionFlags streamEvents
, void (*clientCB
)(struct _CFStream
*, CFStreamEventType
, void *), CFStreamClientContext
*clientCallBackContext
) {
942 Boolean removingClient
= (streamEvents
== kCFStreamEventNone
|| clientCB
== NULL
|| clientCallBackContext
== NULL
);
943 if (removingClient
) {
945 streamEvents
= kCFStreamEventNone
;
946 clientCallBackContext
= NULL
;
948 if (!stream
->client
) {
949 if (removingClient
) {
950 // We have no client now, and we've been asked to add none???
953 _initializeClient(stream
);
954 if (!stream
->client
) {
955 // Asynch not supported
959 if (stream
->client
->cb
&& stream
->client
->cbContext
.release
) {
960 stream
->client
->cbContext
.release(stream
->client
->cbContext
.info
);
962 stream
->client
->cb
= clientCB
;
963 if (clientCallBackContext
) {
964 stream
->client
->cbContext
.version
= clientCallBackContext
->version
;
965 stream
->client
->cbContext
.retain
= clientCallBackContext
->retain
;
966 stream
->client
->cbContext
.release
= clientCallBackContext
->release
;
967 stream
->client
->cbContext
.copyDescription
= clientCallBackContext
->copyDescription
;
968 stream
->client
->cbContext
.info
= (clientCallBackContext
->retain
&& clientCallBackContext
->info
) ? clientCallBackContext
->retain(clientCallBackContext
->info
) : clientCallBackContext
->info
;
970 stream
->client
->cbContext
.retain
= NULL
;
971 stream
->client
->cbContext
.release
= NULL
;
972 stream
->client
->cbContext
.copyDescription
= NULL
;
973 stream
->client
->cbContext
.info
= NULL
;
975 if (stream
->client
->when
!= streamEvents
) {
976 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
977 stream
->client
->when
= streamEvents
;
978 if (cb
->requestEvents
) {
979 cb
->requestEvents(stream
, streamEvents
, _CFStreamGetInfoPointer(stream
));
985 CF_EXPORT Boolean
CFReadStreamSetClient(CFReadStreamRef readStream
, CFOptionFlags streamEvents
, CFReadStreamClientCallBack clientCB
, CFStreamClientContext
*clientContext
) {
986 CF_OBJC_FUNCDISPATCH3(__kCFReadStreamTypeID
, Boolean
, readStream
, "_setCFClientFlags:callback:context:", streamEvents
, clientCB
, clientContext
);
987 streamEvents
&= ~kCFStreamEventCanAcceptBytes
;
988 return _CFStreamSetClient((struct _CFStream
*)readStream
, streamEvents
, (void (*)(struct _CFStream
*, CFStreamEventType
, void *))clientCB
, clientContext
);
991 CF_EXPORT Boolean
CFWriteStreamSetClient(CFWriteStreamRef writeStream
, CFOptionFlags streamEvents
, CFWriteStreamClientCallBack clientCB
, CFStreamClientContext
*clientContext
) {
992 CF_OBJC_FUNCDISPATCH3(__kCFWriteStreamTypeID
, Boolean
, writeStream
, "_setCFClientFlags:callback:context:", streamEvents
, clientCB
, clientContext
);
993 streamEvents
&= ~kCFStreamEventHasBytesAvailable
;
994 return _CFStreamSetClient((struct _CFStream
*)writeStream
, streamEvents
, (void (*)(struct _CFStream
*, CFStreamEventType
, void *))clientCB
, clientContext
);
997 static inline void *_CFStreamGetClient(struct _CFStream
*stream
) {
998 if (stream
->client
) return stream
->client
->cbContext
.info
;
1002 CF_EXPORT
void *_CFReadStreamGetClient(CFReadStreamRef readStream
) {
1003 return _CFStreamGetClient((struct _CFStream
*)readStream
);
1006 CF_EXPORT
void *_CFWriteStreamGetClient(CFWriteStreamRef writeStream
) {
1007 return _CFStreamGetClient((struct _CFStream
*)writeStream
);
1011 __private_extern__
void _CFStreamScheduleWithRunLoop(struct _CFStream
*stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1012 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1014 if (!stream
->client
) {
1015 _initializeClient(stream
);
1016 if (!stream
->client
) return; // we don't support asynch.
1019 if (!stream
->client
->rlSource
) {
1022 CFMutableArrayRef list
;
1028 key
= CFArrayCreate(kCFAllocatorDefault
, a
, sizeof(a
) / sizeof(a
[0]), &kCFTypeArrayCallBacks
);
1030 __CFSpinLock(&sSourceLock
);
1032 if (!sSharedSources
)
1033 sSharedSources
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1035 list
= (CFMutableArrayRef
)CFDictionaryGetValue(sSharedSources
, key
);
1037 stream
->client
->rlSource
= (CFRunLoopSourceRef
)CFRetain(((struct _CFStream
*)CFArrayGetValueAtIndex(list
, 0))->client
->rlSource
);
1041 CFRunLoopSourceContext ctxt
= {
1044 NULL
, // Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop
1045 NULL
, // Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop
1046 (CFStringRef(*)(const void *))CFCopyDescription
,
1047 /*(Boolean(*)(const void *, const void *))CFEqual*/ NULL
,
1048 (CFHashCode(*)(const void *))__CFStreamHash
,
1051 (void(*)(void *))_CFStreamSignalEventSynch
1054 list
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1055 CFDictionaryAddValue(sSharedSources
, key
, list
);
1059 stream
->client
->rlSource
= CFRunLoopSourceCreate(CFGetAllocator(stream
), 0, &ctxt
);
1060 stream
->client
->whatToSignal
= 0;
1062 CFRunLoopAddSource(runLoop
, stream
->client
->rlSource
, runLoopMode
);
1065 CFArrayAppendValue(list
, stream
);
1066 CFDictionaryAddValue(sSharedSources
, stream
, key
);
1071 __CFBitSet(stream
->flags
, SHARED_SOURCE
);
1073 __CFSpinUnlock(&sSourceLock
);
1075 else if (__CFBitIsSet(stream
->flags
, SHARED_SOURCE
)) {
1078 CFMutableArrayRef list
;
1081 CFAllocatorRef alloc
= CFGetAllocator(stream
);
1082 CFRunLoopSourceContext ctxt
= {
1085 NULL
, // Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop
1086 NULL
, // Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop
1087 (CFStringRef(*)(const void *))CFCopyDescription
,
1088 /*(Boolean(*)(const void *, const void *))CFEqual*/ NULL
,
1089 (CFHashCode(*)(const void *))__CFStreamHash
,
1092 (void(*)(void *))_CFStreamSignalEventSynch
1095 __CFSpinLock(&sSourceLock
);
1097 key
= (CFArrayRef
)CFRetain((CFTypeRef
)CFDictionaryGetValue(sSharedSources
, stream
));
1098 list
= (CFMutableArrayRef
)CFDictionaryGetValue(sSharedSources
, key
);
1100 c
= CFArrayGetCount(list
);
1101 i
= CFArrayGetFirstIndexOfValue(list
, CFRangeMake(0, c
), stream
);
1102 if (i
!= kCFNotFound
) {
1103 CFArrayRemoveValueAtIndex(list
, i
);
1108 CFRunLoopRemoveSource((CFRunLoopRef
)CFArrayGetValueAtIndex(key
, 0), stream
->client
->rlSource
, (CFStringRef
)CFArrayGetValueAtIndex(key
, 1));
1109 CFRunLoopSourceInvalidate(stream
->client
->rlSource
);
1110 CFDictionaryRemoveValue(sSharedSources
, key
);
1113 CFDictionaryRemoveValue(sSharedSources
, stream
);
1115 CFRelease(stream
->client
->rlSource
);
1116 __CFBitClear(stream
->flags
, SHARED_SOURCE
);
1118 __CFSpinUnlock(&sSourceLock
);
1120 stream
->client
->rlSource
= CFRunLoopSourceCreate(alloc
, 0, &ctxt
);
1122 CFRunLoopAddSource((CFRunLoopRef
)CFArrayGetValueAtIndex(key
, 0), stream
->client
->rlSource
, (CFStringRef
)CFArrayGetValueAtIndex(key
, 1));
1126 CFRunLoopAddSource(runLoop
, stream
->client
->rlSource
, runLoopMode
);
1128 CFRunLoopAddSource(runLoop
, stream
->client
->rlSource
, runLoopMode
);
1131 if (!stream
->client
->runLoopsAndModes
) {
1132 stream
->client
->runLoopsAndModes
= CFArrayCreateMutable(CFGetAllocator(stream
), 0, &kCFTypeArrayCallBacks
);
1134 CFArrayAppendValue(stream
->client
->runLoopsAndModes
, runLoop
);
1135 CFArrayAppendValue(stream
->client
->runLoopsAndModes
, runLoopMode
);
1138 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1139 cb
->schedule(stream
, runLoop
, runLoopMode
, _CFStreamGetInfoPointer(stream
));
1140 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1144 CF_EXPORT
void CFReadStreamScheduleWithRunLoop(CFReadStreamRef stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1145 CF_OBJC_FUNCDISPATCH2(__kCFReadStreamTypeID
, void, stream
, "_scheduleInCFRunLoop:forMode:", runLoop
, runLoopMode
);
1146 _CFStreamScheduleWithRunLoop((struct _CFStream
*)stream
, runLoop
, runLoopMode
);
1149 CF_EXPORT
void CFWriteStreamScheduleWithRunLoop(CFWriteStreamRef stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1150 CF_OBJC_FUNCDISPATCH2(__kCFWriteStreamTypeID
, void, stream
, "_scheduleInCFRunLoop:forMode:", runLoop
, runLoopMode
);
1151 _CFStreamScheduleWithRunLoop((struct _CFStream
*)stream
, runLoop
, runLoopMode
);
1155 __private_extern__
void _CFStreamUnscheduleFromRunLoop(struct _CFStream
*stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1156 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1157 if (!stream
->client
) return;
1158 if (!stream
->client
->rlSource
) return;
1160 if (!__CFBitIsSet(stream
->flags
, SHARED_SOURCE
)) {
1161 CFRunLoopRemoveSource(runLoop
, stream
->client
->rlSource
, runLoopMode
);
1164 CFMutableArrayRef list
;
1167 __CFSpinLock(&sSourceLock
);
1169 key
= (CFArrayRef
)CFDictionaryGetValue(sSharedSources
, stream
);
1170 list
= (CFMutableArrayRef
)CFDictionaryGetValue(sSharedSources
, key
);
1172 c
= CFArrayGetCount(list
);
1173 i
= CFArrayGetFirstIndexOfValue(list
, CFRangeMake(0, c
), stream
);
1174 if (i
!= kCFNotFound
) {
1175 CFArrayRemoveValueAtIndex(list
, i
);
1180 CFRunLoopRemoveSource(runLoop
, stream
->client
->rlSource
, runLoopMode
);
1181 CFRunLoopSourceInvalidate(stream
->client
->rlSource
);
1182 CFDictionaryRemoveValue(sSharedSources
, key
);
1185 CFDictionaryRemoveValue(sSharedSources
, stream
);
1187 CFRelease(stream
->client
->rlSource
);
1188 stream
->client
->rlSource
= NULL
;
1189 __CFBitClear(stream
->flags
, SHARED_SOURCE
);
1191 __CFSpinUnlock(&sSourceLock
);
1194 _CFStreamRemoveRunLoopAndModeFromArray(stream
->client
->runLoopsAndModes
, runLoop
, runLoopMode
);
1196 if (cb
->unschedule
) {
1197 cb
->unschedule(stream
, runLoop
, runLoopMode
, _CFStreamGetInfoPointer(stream
));
1201 CF_EXPORT
void CFReadStreamUnscheduleFromRunLoop(CFReadStreamRef stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1202 CF_OBJC_FUNCDISPATCH2(__kCFReadStreamTypeID
, void, stream
, "_unscheduleFromCFRunLoop:forMode:", runLoop
, runLoopMode
);
1203 _CFStreamUnscheduleFromRunLoop((struct _CFStream
*)stream
, runLoop
, runLoopMode
);
1206 void CFWriteStreamUnscheduleFromRunLoop(CFWriteStreamRef stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1207 CF_OBJC_FUNCDISPATCH2(__kCFWriteStreamTypeID
, void, stream
, "_unscheduleFromCFRunLoop:forMode:", runLoop
, runLoopMode
);
1208 _CFStreamUnscheduleFromRunLoop((struct _CFStream
*)stream
, runLoop
, runLoopMode
);
1211 static void waitForOpen(struct _CFStream
*stream
) {
1212 CFRunLoopRef runLoop
= CFRunLoopGetCurrent();
1213 CFStringRef privateMode
= CFSTR("_kCFStreamBlockingOpenMode");
1214 _CFStreamScheduleWithRunLoop(stream
, runLoop
, privateMode
);
1215 // 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....
1216 while (__CFStreamGetStatus(stream
) == kCFStreamStatusOpening
) {
1217 CFRunLoopRunInMode(privateMode
, 1e+20, TRUE
);
1219 _CFStreamUnscheduleFromRunLoop(stream
, runLoop
, privateMode
);
1222 static inline CFArrayRef
_CFStreamGetRunLoopsAndModes(struct _CFStream
*stream
) {
1223 if (stream
->client
) return stream
->client
->runLoopsAndModes
;
1227 CF_EXPORT CFArrayRef
_CFReadStreamGetRunLoopsAndModes(CFReadStreamRef readStream
) {
1228 return _CFStreamGetRunLoopsAndModes((struct _CFStream
*)readStream
);
1231 CF_EXPORT CFArrayRef
_CFWriteStreamGetRunLoopsAndModes(CFWriteStreamRef writeStream
) {
1232 return _CFStreamGetRunLoopsAndModes((struct _CFStream
*)writeStream
);
1235 CF_EXPORT
void CFReadStreamSignalEvent(CFReadStreamRef stream
, CFStreamEventType event
, CFStreamError
*error
) {
1236 _CFStreamSignalEvent((struct _CFStream
*)stream
, event
, error
, TRUE
);
1239 CF_EXPORT
void CFWriteStreamSignalEvent(CFWriteStreamRef stream
, CFStreamEventType event
, CFStreamError
*error
) {
1240 _CFStreamSignalEvent((struct _CFStream
*)stream
, event
, error
, TRUE
);
1243 CF_EXPORT
void _CFReadStreamSignalEventDelayed(CFReadStreamRef stream
, CFStreamEventType event
, CFStreamError
*error
) {
1244 _CFStreamSignalEvent((struct _CFStream
*)stream
, event
, error
, FALSE
);
1247 CF_EXPORT
void _CFWriteStreamSignalEventDelayed(CFWriteStreamRef stream
, CFStreamEventType event
, CFStreamError
*error
) {
1248 _CFStreamSignalEvent((struct _CFStream
*)stream
, event
, error
, FALSE
);
1251 CF_EXPORT
void *CFReadStreamGetInfoPointer(CFReadStreamRef stream
) {
1252 return _CFStreamGetInfoPointer((struct _CFStream
*)stream
);
1255 CF_EXPORT
void *CFWriteStreamGetInfoPointer(CFWriteStreamRef stream
) {
1256 return _CFStreamGetInfoPointer((struct _CFStream
*)stream
);
1259 #if defined(__MACH__)
1261 #pragma mark Scheduling Convenience Routines
1265 void _CFStreamSourceScheduleWithRunLoop(CFRunLoopSourceRef source
, CFMutableArrayRef runLoopsAndModes
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
)
1270 count
= CFArrayGetCount(runLoopsAndModes
);
1271 range
= CFRangeMake(0, count
);
1273 while (range
.length
) {
1275 CFIndex i
= CFArrayGetFirstIndexOfValue(runLoopsAndModes
, range
, runLoop
);
1277 if (i
== kCFNotFound
)
1280 if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes
, i
+ 1), runLoopMode
))
1283 range
.location
= i
+ 2;
1284 range
.length
= count
- range
.location
;
1287 // Add the new values.
1288 CFArrayAppendValue(runLoopsAndModes
, runLoop
);
1289 CFArrayAppendValue(runLoopsAndModes
, runLoopMode
);
1291 // Schedule the source on the new loop and mode.
1293 CFRunLoopAddSource(runLoop
, source
, runLoopMode
);
1298 void _CFStreamSourceUnscheduleFromRunLoop(CFRunLoopSourceRef source
, CFMutableArrayRef runLoopsAndModes
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
)
1303 count
= CFArrayGetCount(runLoopsAndModes
);
1304 range
= CFRangeMake(0, count
);
1306 while (range
.length
) {
1308 CFIndex i
= CFArrayGetFirstIndexOfValue(runLoopsAndModes
, range
, runLoop
);
1310 // If not found, it's not scheduled on it.
1311 if (i
== kCFNotFound
)
1314 // Make sure it is scheduled in this mode.
1315 if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes
, i
+ 1), runLoopMode
)) {
1317 // Remove mode and runloop from the list.
1318 CFArrayReplaceValues(runLoopsAndModes
, CFRangeMake(i
, 2), NULL
, 0);
1320 // Remove it from the runloop.
1322 CFRunLoopRemoveSource(runLoop
, source
, runLoopMode
);
1327 range
.location
= i
+ 2;
1328 range
.length
= count
- range
.location
;
1334 void _CFStreamSourceScheduleWithAllRunLoops(CFRunLoopSourceRef source
, CFArrayRef runLoopsAndModes
)
1336 CFIndex i
, count
= CFArrayGetCount(runLoopsAndModes
);
1341 for (i
= 0; i
< count
; i
+= 2) {
1343 // Make sure it's scheduled on all the right loops and modes.
1344 // Go through the array adding the source to all loops and modes.
1345 CFRunLoopAddSource((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoopsAndModes
, i
),
1347 (CFStringRef
)CFArrayGetValueAtIndex(runLoopsAndModes
, i
+ 1));
1353 void _CFStreamSourceUncheduleFromAllRunLoops(CFRunLoopSourceRef source
, CFArrayRef runLoopsAndModes
)
1355 CFIndex i
, count
= CFArrayGetCount(runLoopsAndModes
);
1360 for (i
= 0; i
< count
; i
+= 2) {
1362 // Go through the array removing the source from all loops and modes.
1363 CFRunLoopRemoveSource((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoopsAndModes
, i
),
1365 (CFStringRef
)CFArrayGetValueAtIndex(runLoopsAndModes
, i
+ 1));
1369 Boolean
_CFStreamRemoveRunLoopAndModeFromArray(CFMutableArrayRef runLoopsAndModes
, CFRunLoopRef rl
, CFStringRef mode
) {
1371 Boolean found
= FALSE
;
1373 if (!runLoopsAndModes
) return FALSE
;
1375 cnt
= CFArrayGetCount(runLoopsAndModes
);
1376 for (idx
= 0; idx
+ 1 < cnt
; idx
+= 2) {
1377 if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes
, idx
), rl
) && CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes
, idx
+ 1), mode
)) {
1378 CFArrayRemoveValueAtIndex(runLoopsAndModes
, idx
);
1379 CFArrayRemoveValueAtIndex(runLoopsAndModes
, idx
);
1388 #if defined(__WIN32__)
1390 void __CFStreamCleanup(void) {
1391 __CFSpinLock(&sSourceLock
);
1392 if (sSharedSources
) {
1393 CFIndex count
= CFDictionaryGetCount(sSharedSources
);
1395 // Only release if empty. If it's still holding streams (which would be a client
1396 // bug leak), freeing this dict would free the streams, which then need to access the
1397 // dict to remove themselves, which leads to a deadlock.
1398 CFRelease(sSharedSources
);
1399 sSharedSources
= NULL
;
1401 fprintf(stderr
, "*** CFNetwork is shutting down, but %ld streams are still scheduled.\n", count
);
1403 __CFSpinUnlock(&sSourceLock
);