]> git.saurik.com Git - apple/cf.git/blob - CFStream.c
b4c52fd9cb19f0212a6825133095da5aaf3a106d
[apple/cf.git] / CFStream.c
1 /*
2 * Copyright (c) 2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /* CFStream.c
25 Copyright (c) 2000-2012, Apple Inc. All rights reserved.
26 Responsibility: John Iarocci
27 */
28
29 #include <CoreFoundation/CFRuntime.h>
30 #include <CoreFoundation/CFNumber.h>
31 #include <string.h>
32 #include "CFStreamInternal.h"
33 #include "CFInternal.h"
34 #include <stdio.h>
35
36 #if defined(DEBUG)
37 #include <assert.h>
38 #endif
39
40
41 struct CFStreamAux {
42 CFSpinLock_t streamLock;
43 CFArrayRef previousRunloopsAndModes;
44 };
45
46 enum {
47 MIN_STATUS_CODE_BIT = 0,
48 // ..status bits...
49 MAX_STATUS_CODE_BIT = 4,
50
51 CONSTANT_CALLBACKS = 5,
52 CALLING_CLIENT = 6, // MUST remain 6 since it's value is used elsewhere.
53
54 HAVE_CLOSED = 7,
55
56 // Values above used to be defined and others may rely on their values
57
58 // Values below should not matter if they are re-ordered or shift
59
60 SHARED_SOURCE
61 };
62
63
64 /* CALLING_CLIENT really determines whether stream events will be sent to the client immediately, or posted for the next time through the runloop. Since the client may not be prepared for re-entrancy, we must always set/clear this bit around public entry points. -- REW, 9/5/2001
65 Also, CALLING_CLIENT is now used from CFFilteredStream.c (which has a copy of the #define above). Really gross. We should find a way to avoid that.... -- REW, 3/27/2002 */
66 // Used in CFNetwork too
67
68 /* sSharesSources holds two mappings, one the inverse of the other, between a stream and the
69 RunLoop+RunLoopMode pair that it's scheduled in. If the stream is scheduled in more than
70 one loop or mode, it can't share RunLoopSources with others, and is not in this dict.
71 */
72 static CFSpinLock_t sSourceLock = CFSpinLockInit;
73 static CFMutableDictionaryRef sSharedSources = NULL;
74
75 static CFTypeID __kCFReadStreamTypeID = _kCFRuntimeNotATypeID;
76 static CFTypeID __kCFWriteStreamTypeID = _kCFRuntimeNotATypeID;
77
78 // Just reads the bits, for those cases where we don't want to go through any callback checking
79 #define __CFStreamGetStatus(x) __CFBitfieldGetValue((x)->flags, MAX_STATUS_CODE_BIT, MIN_STATUS_CODE_BIT)
80
81 __private_extern__ CFStreamStatus _CFStreamGetStatus(struct _CFStream *stream);
82 static Boolean _CFStreamRemoveRunLoopAndModeFromArray(CFMutableArrayRef runLoopsAndModes, CFRunLoopRef rl, CFStringRef mode);
83 static void _wakeUpRunLoop(struct _CFStream *stream);
84
85 CF_INLINE void checkRLMArray(CFArrayRef arr)
86 {
87 #if defined(DEBUG)
88 assert(arr == NULL || (CFArrayGetCount(arr) % 2) == 0);
89 #endif
90 }
91
92 CF_INLINE void* _CFStreamCreateReserved(CFAllocatorRef alloc) {
93 struct CFStreamAux* aux = (struct CFStreamAux*) CFAllocatorAllocate(alloc, sizeof(struct CFStreamAux), 0);
94 if (aux) {
95 aux->streamLock = CFSpinLockInit;
96 aux->previousRunloopsAndModes = NULL;
97 }
98 return aux;
99 }
100
101 CF_INLINE void _CFStreamDestroyReserved(CFAllocatorRef alloc, void* aux) {
102 struct CFStreamAux* paux = (struct CFStreamAux*) aux;
103 if (paux->previousRunloopsAndModes)
104 CFRelease(paux->previousRunloopsAndModes);
105 CFAllocatorDeallocate(alloc, aux);
106 }
107
108 CF_INLINE struct CFStreamAux* _CFStreamGetAuxRecord(struct _CFStream* stream) {
109 return (struct CFStreamAux*) stream->_reserved1;
110 }
111
112 CF_INLINE void _CFStreamLock(struct _CFStream* stream) {
113 __CFSpinLock(&_CFStreamGetAuxRecord(stream)->streamLock);
114 }
115
116 CF_INLINE void _CFStreamUnlock(struct _CFStream* stream) {
117 __CFSpinUnlock(&_CFStreamGetAuxRecord(stream)->streamLock);
118 }
119
120 CF_INLINE CFRunLoopSourceRef _CFStreamCopySource(struct _CFStream* stream) {
121 CFRunLoopSourceRef source = NULL;
122
123 if (stream) {
124 _CFStreamLock(stream);
125
126 if (stream->client)
127 source = stream->client->rlSource;
128
129 if (source)
130 CFRetain(source);
131
132 _CFStreamUnlock(stream);
133 }
134
135 return source;
136 }
137
138 CF_INLINE void _CFStreamSetSource(struct _CFStream* stream, CFRunLoopSourceRef source, Boolean invalidateOldSource) {
139 CFRunLoopSourceRef oldSource = NULL;
140
141 if (stream) {
142 _CFStreamLock(stream);
143 if (stream->client) {
144 oldSource = stream->client->rlSource;
145 if (oldSource != NULL)
146 CFRetain(oldSource);
147
148 stream->client->rlSource = source;
149 if (source != NULL)
150 CFRetain(source);
151 }
152 _CFStreamUnlock(stream);
153 }
154
155 if (oldSource) {
156 // Lose our extra retain
157 CFRelease(oldSource);
158
159 if (invalidateOldSource)
160 CFRunLoopSourceInvalidate(oldSource);
161
162 // And lose the one that held it in our stream as well
163 CFRelease(oldSource);
164 }
165 }
166
167 CF_INLINE const struct _CFStreamCallBacks *_CFStreamGetCallBackPtr(struct _CFStream *stream) {
168 return stream->callBacks;
169 }
170
171 CF_INLINE void _CFStreamSetStatusCode(struct _CFStream *stream, CFStreamStatus newStatus) {
172 CFStreamStatus status = __CFStreamGetStatus(stream);
173 if (((status != kCFStreamStatusClosed) && (status != kCFStreamStatusError)) ||
174 ((status == kCFStreamStatusClosed) && (newStatus == kCFStreamStatusError)))
175 {
176 __CFBitfieldSetValue(stream->flags, MAX_STATUS_CODE_BIT, MIN_STATUS_CODE_BIT, newStatus);
177 }
178 }
179
180 CF_INLINE void _CFStreamScheduleEvent(struct _CFStream *stream, CFStreamEventType event) {
181 if (stream->client && (stream->client->when & event)) {
182 CFRunLoopSourceRef source = _CFStreamCopySource(stream);
183 if (source) {
184 stream->client->whatToSignal |= event;
185
186 CFRunLoopSourceSignal(source);
187 CFRelease(source);
188 _wakeUpRunLoop(stream);
189 }
190 }
191 }
192
193 CF_INLINE void _CFStreamSetStreamError(struct _CFStream *stream, CFStreamError *err) {
194 if (!stream->error) {
195 stream->error = (CFErrorRef)CFAllocatorAllocate(CFGetAllocator(stream), sizeof(CFStreamError), 0);
196 }
197 memmove(stream->error, err, sizeof(CFStreamError));
198 }
199
200 static CFStringRef __CFStreamCopyDescription(CFTypeRef cf) {
201 struct _CFStream *stream = (struct _CFStream *)cf;
202 const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
203 CFStringRef contextDescription;
204 CFStringRef desc;
205 if (cb->copyDescription) {
206 if (cb->version == 0) {
207 contextDescription = ((CFStringRef(*)(void *))cb->copyDescription)(_CFStreamGetInfoPointer(stream));
208 } else {
209 contextDescription = cb->copyDescription(stream, _CFStreamGetInfoPointer(stream));
210 }
211 } else {
212 contextDescription = CFStringCreateWithFormat(CFGetAllocator(stream), NULL, CFSTR("info = %p"), _CFStreamGetInfoPointer(stream));
213 }
214 if (CFGetTypeID(cf) == __kCFReadStreamTypeID) {
215 desc = CFStringCreateWithFormat(CFGetAllocator(stream), NULL, CFSTR("<CFReadStream %p>{%@}"), stream, contextDescription);
216 } else {
217 desc = CFStringCreateWithFormat(CFGetAllocator(stream), NULL, CFSTR("<CFWriteStream %p>{%@}"), stream, contextDescription);
218 }
219 CFRelease(contextDescription);
220 return desc;
221 }
222
223 static void _CFStreamDetachSource(struct _CFStream* stream) {
224 if (stream && stream->client && stream->client->rlSource) {
225 if (!__CFBitIsSet(stream->flags, SHARED_SOURCE)) {
226 _CFStreamSetSource(stream, NULL, TRUE);
227 }
228 else {
229
230 CFArrayRef runLoopAndSourceKey;
231 CFMutableArrayRef list;
232 CFIndex count;
233 CFIndex i;
234
235 __CFSpinLock(&sSourceLock);
236
237 runLoopAndSourceKey = (CFArrayRef)CFDictionaryGetValue(sSharedSources, stream);
238 list = (CFMutableArrayRef)CFDictionaryGetValue(sSharedSources, runLoopAndSourceKey);
239
240 count = CFArrayGetCount(list);
241 i = CFArrayGetFirstIndexOfValue(list, CFRangeMake(0, count), stream);
242 if (i != kCFNotFound) {
243 CFArrayRemoveValueAtIndex(list, i);
244 count--;
245 }
246
247 CFAssert(CFArrayGetFirstIndexOfValue(list, CFRangeMake(0, CFArrayGetCount(list)), stream) == kCFNotFound, __kCFLogAssertion, "CFStreamClose: stream found twice in its shared source's list");
248
249 if (count == 0) {
250 CFRunLoopSourceRef source = _CFStreamCopySource(stream);
251 if (source) {
252 CFRunLoopRemoveSource((CFRunLoopRef)CFArrayGetValueAtIndex(runLoopAndSourceKey, 0), source, (CFStringRef)CFArrayGetValueAtIndex(runLoopAndSourceKey, 1));
253 CFRelease(source);
254 }
255 CFDictionaryRemoveValue(sSharedSources, runLoopAndSourceKey);
256 }
257
258 CFDictionaryRemoveValue(sSharedSources, stream);
259
260 _CFStreamSetSource(stream, NULL, count == 0);
261
262 __CFBitClear(stream->flags, SHARED_SOURCE);
263
264 __CFSpinUnlock(&sSourceLock);
265 }
266 }
267 }
268
269 __private_extern__ void _CFStreamClose(struct _CFStream *stream) {
270 CFStreamStatus status = _CFStreamGetStatus(stream);
271 const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
272 if (status == kCFStreamStatusNotOpen || status == kCFStreamStatusClosed || (status == kCFStreamStatusError && __CFBitIsSet(stream->flags, HAVE_CLOSED))) {
273 // Stream is not open from the client's perspective; do not callout and do not update our status to "closed"
274 return;
275 }
276 __CFBitSet(stream->flags, HAVE_CLOSED);
277 __CFBitSet(stream->flags, CALLING_CLIENT);
278 if (cb->close) {
279 cb->close(stream, _CFStreamGetInfoPointer(stream));
280 }
281 if (stream->client) {
282 _CFStreamDetachSource(stream);
283 }
284 _CFStreamSetStatusCode(stream, kCFStreamStatusClosed);
285 __CFBitClear(stream->flags, CALLING_CLIENT);
286 }
287
288 //static int numStreamInstances = 0;
289
290 static void __CFStreamDeallocate(CFTypeRef cf) {
291 struct _CFStream *stream = (struct _CFStream *)cf;
292 const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
293 CFAllocatorRef alloc = CFGetAllocator(stream);
294 // numStreamInstances --;
295
296 // Close the stream
297 _CFStreamClose(stream);
298
299 if (stream->client) {
300 CFStreamClientContext *cbContext;
301 cbContext = &(stream->client->cbContext);
302 if (cbContext->info && cbContext->release) {
303 cbContext->release(cbContext->info);
304 }
305 _CFStreamDetachSource(stream);
306 if (stream->client->runLoopsAndModes) {
307 CFRelease(stream->client->runLoopsAndModes);
308 }
309
310 CFAllocatorDeallocate(alloc, stream->client);
311 stream->client = NULL; // Just in case finalize, below, calls back in to us
312 }
313 if (cb->finalize) {
314 if (cb->version == 0) {
315 ((void(*)(void *))cb->finalize)(_CFStreamGetInfoPointer(stream));
316 } else {
317 cb->finalize(stream, _CFStreamGetInfoPointer(stream));
318 }
319 }
320 if (stream->error) {
321 if (cb->version < 2) {
322 CFAllocatorDeallocate(alloc, stream->error);
323 } else {
324 CFRelease(stream->error);
325 }
326 }
327 if (!__CFBitIsSet(stream->flags, CONSTANT_CALLBACKS)) {
328 CFAllocatorDeallocate(alloc, (void *)stream->callBacks);
329 }
330 if (stream->_reserved1)
331 _CFStreamDestroyReserved(alloc, stream->_reserved1);
332 }
333
334 static const CFRuntimeClass __CFReadStreamClass = {
335 0,
336 "CFReadStream",
337 NULL, // init
338 NULL, // copy
339 __CFStreamDeallocate,
340 NULL,
341 NULL,
342 NULL, // copyHumanDesc
343 __CFStreamCopyDescription
344 };
345
346 static const CFRuntimeClass __CFWriteStreamClass = {
347 0,
348 "CFWriteStream",
349 NULL, // init
350 NULL, // copy
351 __CFStreamDeallocate,
352 NULL,
353 NULL,
354 NULL, // copyHumanDesc
355 __CFStreamCopyDescription
356 };
357
358 CONST_STRING_DECL(kCFStreamPropertySocketNativeHandle, "kCFStreamPropertySocketNativeHandle")
359 CONST_STRING_DECL(kCFStreamPropertySocketRemoteHostName, "kCFStreamPropertySocketRemoteHostName")
360 CONST_STRING_DECL(kCFStreamPropertySocketRemotePortNumber, "kCFStreamPropertySocketRemotePortNumber")
361 CONST_STRING_DECL(kCFStreamPropertyDataWritten, "kCFStreamPropertyDataWritten")
362 CONST_STRING_DECL(kCFStreamPropertyAppendToFile, "kCFStreamPropertyAppendToFile")
363
364 __private_extern__ void __CFStreamInitialize(void) {
365 __kCFReadStreamTypeID = _CFRuntimeRegisterClass(&__CFReadStreamClass);
366 __kCFWriteStreamTypeID = _CFRuntimeRegisterClass(&__CFWriteStreamClass);
367 }
368
369
370 CF_EXPORT CFTypeID CFReadStreamGetTypeID(void) {
371 return __kCFReadStreamTypeID;
372 }
373
374 CF_EXPORT CFTypeID CFWriteStreamGetTypeID(void) {
375 return __kCFWriteStreamTypeID;
376 }
377
378 static struct _CFStream *_CFStreamCreate(CFAllocatorRef allocator, Boolean isReadStream) {
379 struct _CFStream *newStream = (struct _CFStream *)_CFRuntimeCreateInstance(allocator, isReadStream ? __kCFReadStreamTypeID : __kCFWriteStreamTypeID, sizeof(struct _CFStream) - sizeof(CFRuntimeBase), NULL);
380 if (newStream) {
381 // numStreamInstances ++;
382 newStream->flags = 0;
383 _CFStreamSetStatusCode(newStream, kCFStreamStatusNotOpen);
384 newStream->error = NULL;
385 newStream->client = NULL;
386 newStream->info = NULL;
387 newStream->callBacks = NULL;
388
389 newStream->_reserved1 = _CFStreamCreateReserved(allocator);
390 }
391 return newStream;
392 }
393
394 __private_extern__ struct _CFStream *_CFStreamCreateWithConstantCallbacks(CFAllocatorRef alloc, void *info, const struct _CFStreamCallBacks *cb, Boolean isReading) {
395 struct _CFStream *newStream;
396 if (cb->version != 1) return NULL;
397 newStream = _CFStreamCreate(alloc, isReading);
398 if (newStream) {
399 __CFBitSet(newStream->flags, CONSTANT_CALLBACKS);
400 newStream->callBacks = cb;
401 if (cb->create) {
402 newStream->info = cb->create(newStream, info);
403 } else {
404 newStream->info = info;
405 }
406 }
407 return newStream;
408 }
409
410 CF_EXPORT void _CFStreamSetInfoPointer(struct _CFStream *stream, void *info, const struct _CFStreamCallBacks *cb) {
411 if (info != stream->info) {
412 if (stream->callBacks->finalize) {
413 stream->callBacks->finalize(stream, stream->info);
414 }
415 if (cb->create) {
416 stream->info = cb->create(stream, info);
417 } else {
418 stream->info = info;
419 }
420 }
421 stream->callBacks = cb;
422 }
423
424
425 CF_EXPORT CFReadStreamRef CFReadStreamCreate(CFAllocatorRef alloc, const CFReadStreamCallBacks *callbacks, void *info) {
426 struct _CFStream *newStream = _CFStreamCreate(alloc, TRUE);
427 struct _CFStreamCallBacks *cb;
428 if (!newStream) return NULL;
429 cb = (struct _CFStreamCallBacks *)CFAllocatorAllocate(alloc, sizeof(struct _CFStreamCallBacks), 0);
430 if (!cb) {
431 CFRelease(newStream);
432 return NULL;
433 }
434 if (callbacks->version == 0) {
435 CFReadStreamCallBacksV0 *cbV0 = (CFReadStreamCallBacksV0 *)callbacks;
436 CFStreamClientContext *ctxt = (CFStreamClientContext *)info;
437 newStream->info = ctxt->retain ? (void *)ctxt->retain(ctxt->info) : ctxt->info;
438 cb->version = 0;
439 cb->create = (void *(*)(struct _CFStream *, void *))ctxt->retain;
440 cb->finalize = (void(*)(struct _CFStream *, void *))ctxt->release;
441 cb->copyDescription = (CFStringRef(*)(struct _CFStream *, void *))ctxt->copyDescription;
442 cb->open = (Boolean(*)(struct _CFStream *, CFErrorRef *, Boolean *, void *))cbV0->open;
443 cb->openCompleted = (Boolean (*)(struct _CFStream *, CFErrorRef *, void *))cbV0->openCompleted;
444 cb->read = (CFIndex (*)(CFReadStreamRef, UInt8 *, CFIndex, CFErrorRef *, Boolean *, void *))cbV0->read;
445 cb->getBuffer = (const UInt8 *(*)(CFReadStreamRef, CFIndex, CFIndex *, CFErrorRef *, Boolean *, void *))cbV0->getBuffer;
446 cb->canRead = (Boolean (*)(CFReadStreamRef, CFErrorRef*, void*))cbV0->canRead;
447 cb->write = NULL;
448 cb->canWrite = NULL;
449 cb->close = (void (*)(struct _CFStream *, void *))cbV0->close;
450 cb->copyProperty = (CFTypeRef (*)(struct _CFStream *, CFStringRef, void *))cbV0->copyProperty;
451 cb->setProperty = NULL;
452 cb->requestEvents = NULL;
453 cb->schedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))cbV0->schedule;
454 cb->unschedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))cbV0->unschedule;
455 } else if (callbacks->version == 1) {
456 CFReadStreamCallBacksV1 *cbV1 = (CFReadStreamCallBacksV1 *)callbacks;
457 newStream->info = cbV1->create ? cbV1->create((CFReadStreamRef)newStream, info) : info;
458 cb->version = 1;
459 cb->create = (void *(*)(struct _CFStream *, void *))cbV1->create;
460 cb->finalize = (void(*)(struct _CFStream *, void *))cbV1->finalize;
461 cb->copyDescription = (CFStringRef(*)(struct _CFStream *, void *))cbV1->copyDescription;
462 cb->open = (Boolean(*)(struct _CFStream *, CFErrorRef *, Boolean *, void *))cbV1->open;
463 cb->openCompleted = (Boolean (*)(struct _CFStream *, CFErrorRef *, void *))cbV1->openCompleted;
464 cb->read = (CFIndex (*)(CFReadStreamRef, UInt8 *, CFIndex, CFErrorRef *, Boolean *, void *))cbV1->read;
465 cb->getBuffer = (const UInt8 *(*)(CFReadStreamRef, CFIndex, CFIndex *, CFErrorRef *, Boolean *, void *))cbV1->getBuffer;
466 cb->canRead = (Boolean (*)(CFReadStreamRef, CFErrorRef*, void*))cbV1->canRead;
467 cb->write = NULL;
468 cb->canWrite = NULL;
469 cb->close = (void (*)(struct _CFStream *, void *))cbV1->close;
470 cb->copyProperty = (CFTypeRef (*)(struct _CFStream *, CFStringRef, void *))cbV1->copyProperty;
471 cb->setProperty = (Boolean(*)(struct _CFStream *, CFStringRef, CFTypeRef, void *))cbV1->setProperty;
472 cb->requestEvents = (void(*)(struct _CFStream *, CFOptionFlags, void *))cbV1->requestEvents;
473 cb->schedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))cbV1->schedule;
474 cb->unschedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))cbV1->unschedule;
475 } else {
476 newStream->info = callbacks->create ? callbacks->create((CFReadStreamRef)newStream, info) : info;
477 cb->version = 2;
478 cb->create = (void *(*)(struct _CFStream *, void *))callbacks->create;
479 cb->finalize = (void(*)(struct _CFStream *, void *))callbacks->finalize;
480 cb->copyDescription = (CFStringRef(*)(struct _CFStream *, void *))callbacks->copyDescription;
481 cb->open = (Boolean(*)(struct _CFStream *, CFErrorRef *, Boolean *, void *))callbacks->open;
482 cb->openCompleted = (Boolean (*)(struct _CFStream *, CFErrorRef *, void *))callbacks->openCompleted;
483 cb->read = callbacks->read;
484 cb->getBuffer = callbacks->getBuffer;
485 cb->canRead = callbacks->canRead;
486 cb->write = NULL;
487 cb->canWrite = NULL;
488 cb->close = (void (*)(struct _CFStream *, void *))callbacks->close;
489 cb->copyProperty = (CFTypeRef (*)(struct _CFStream *, CFStringRef, void *))callbacks->copyProperty;
490 cb->setProperty = (Boolean(*)(struct _CFStream *, CFStringRef, CFTypeRef, void *))callbacks->setProperty;
491 cb->requestEvents = (void(*)(struct _CFStream *, CFOptionFlags, void *))callbacks->requestEvents;
492 cb->schedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))callbacks->schedule;
493 cb->unschedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))callbacks->unschedule;
494 }
495
496 newStream->callBacks = cb;
497 return (CFReadStreamRef)newStream;
498 }
499
500 CF_EXPORT CFWriteStreamRef CFWriteStreamCreate(CFAllocatorRef alloc, const CFWriteStreamCallBacks *callbacks, void *info) {
501 struct _CFStream *newStream = _CFStreamCreate(alloc, FALSE);
502 struct _CFStreamCallBacks *cb;
503 if (!newStream) return NULL;
504 cb = (struct _CFStreamCallBacks *)CFAllocatorAllocate(alloc, sizeof(struct _CFStreamCallBacks), 0);
505 if (!cb) {
506 CFRelease(newStream);
507 return NULL;
508 }
509 if (callbacks->version == 0) {
510 CFWriteStreamCallBacksV0 *cbV0 = (CFWriteStreamCallBacksV0 *)callbacks;
511 CFStreamClientContext *ctxt = (CFStreamClientContext *)info;
512 newStream->info = ctxt->retain ? (void *)ctxt->retain(ctxt->info) : ctxt->info;
513 cb->version = 0;
514 cb->create = (void *(*)(struct _CFStream *, void *))ctxt->retain;
515 cb->finalize = (void(*)(struct _CFStream *, void *))ctxt->release;
516 cb->copyDescription = (CFStringRef(*)(struct _CFStream *, void *))ctxt->copyDescription;
517 cb->open = (Boolean(*)(struct _CFStream *, CFErrorRef *, Boolean *, void *))cbV0->open;
518 cb->openCompleted = (Boolean (*)(struct _CFStream *, CFErrorRef *, void *))cbV0->openCompleted;
519 cb->read = NULL;
520 cb->getBuffer = NULL;
521 cb->canRead = NULL;
522 cb->write = (CFIndex(*)(CFWriteStreamRef stream, const UInt8 *buffer, CFIndex bufferLength, CFErrorRef *error, void *info))cbV0->write;
523 cb->canWrite = (Boolean(*)(CFWriteStreamRef stream, CFErrorRef *error, void *info))cbV0->canWrite;
524 cb->close = (void (*)(struct _CFStream *, void *))cbV0->close;
525 cb->copyProperty = (CFTypeRef (*)(struct _CFStream *, CFStringRef, void *))cbV0->copyProperty;
526 cb->setProperty = NULL;
527 cb->requestEvents = NULL;
528 cb->schedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))cbV0->schedule;
529 cb->unschedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))cbV0->unschedule;
530 } else if (callbacks->version == 1) {
531 CFWriteStreamCallBacksV1 *cbV1 = (CFWriteStreamCallBacksV1 *)callbacks;
532 cb->version = 1;
533 newStream->info = cbV1->create ? cbV1->create((CFWriteStreamRef)newStream, info) : info;
534 cb->create = (void *(*)(struct _CFStream *, void *))cbV1->create;
535 cb->finalize = (void(*)(struct _CFStream *, void *))cbV1->finalize;
536 cb->copyDescription = (CFStringRef(*)(struct _CFStream *, void *))cbV1->copyDescription;
537 cb->open = (Boolean(*)(struct _CFStream *, CFErrorRef *, Boolean *, void *))cbV1->open;
538 cb->openCompleted = (Boolean (*)(struct _CFStream *, CFErrorRef *, void *))cbV1->openCompleted;
539 cb->read = NULL;
540 cb->getBuffer = NULL;
541 cb->canRead = NULL;
542 cb->write = (CFIndex(*)(CFWriteStreamRef stream, const UInt8 *buffer, CFIndex bufferLength, CFErrorRef *error, void *info))cbV1->write;
543 cb->canWrite = (Boolean(*)(CFWriteStreamRef stream, CFErrorRef *error, void *info))cbV1->canWrite;
544 cb->close = (void (*)(struct _CFStream *, void *))cbV1->close;
545 cb->copyProperty = (CFTypeRef (*)(struct _CFStream *, CFStringRef, void *))cbV1->copyProperty;
546 cb->setProperty = (Boolean (*)(struct _CFStream *, CFStringRef, CFTypeRef, void *))cbV1->setProperty;
547 cb->requestEvents = (void(*)(struct _CFStream *, CFOptionFlags, void *))cbV1->requestEvents;
548 cb->schedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))cbV1->schedule;
549 cb->unschedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))cbV1->unschedule;
550 } else {
551 cb->version = callbacks->version;
552 newStream->info = callbacks->create ? callbacks->create((CFWriteStreamRef)newStream, info) : info;
553 cb->create = (void *(*)(struct _CFStream *, void *))callbacks->create;
554 cb->finalize = (void(*)(struct _CFStream *, void *))callbacks->finalize;
555 cb->copyDescription = (CFStringRef(*)(struct _CFStream *, void *))callbacks->copyDescription;
556 cb->open = (Boolean(*)(struct _CFStream *, CFErrorRef *, Boolean *, void *))callbacks->open;
557 cb->openCompleted = (Boolean (*)(struct _CFStream *, CFErrorRef *, void *))callbacks->openCompleted;
558 cb->read = NULL;
559 cb->getBuffer = NULL;
560 cb->canRead = NULL;
561 cb->write = callbacks->write;
562 cb->canWrite = callbacks->canWrite;
563 cb->close = (void (*)(struct _CFStream *, void *))callbacks->close;
564 cb->copyProperty = (CFTypeRef (*)(struct _CFStream *, CFStringRef, void *))callbacks->copyProperty;
565 cb->setProperty = (Boolean (*)(struct _CFStream *, CFStringRef, CFTypeRef, void *))callbacks->setProperty;
566 cb->requestEvents = (void(*)(struct _CFStream *, CFOptionFlags, void *))callbacks->requestEvents;
567 cb->schedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))callbacks->schedule;
568 cb->unschedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))callbacks->unschedule;
569 }
570 newStream->callBacks = cb;
571 return (CFWriteStreamRef)newStream;
572 }
573
574 static void _signalEventSync(struct _CFStream* stream, CFOptionFlags whatToSignal)
575 {
576 CFOptionFlags eventMask;
577
578 __CFBitSet(stream->flags, CALLING_CLIENT);
579
580 void* info = NULL;
581 void (*release) (void*) = NULL;
582
583 if (stream->client->cbContext.retain == NULL)
584 info = stream->client->cbContext.info;
585 else {
586 info = stream->client->cbContext.retain(stream->client->cbContext.info);
587 release = stream->client->cbContext.release;
588 }
589
590 for (eventMask = 1; eventMask <= whatToSignal; eventMask = eventMask << 1) {
591 if ((eventMask & whatToSignal) && (stream->client->when & eventMask)) {
592 stream->client->cb(stream, eventMask, info);
593
594 /* What happens if the callback sets the client to NULL? We're in a loop here... Hmm. */
595 /* After writing that comment, I see: <rdar://problem/6793636> CFReadStreamSetClient(..., NULL) unsafely releases info pointer immediately */
596 /* Of note, when the stream callbacks are set to to NULL, we're re-initalized so as not to receive more events, so we
597 * should break pout of this loop */
598 }
599 }
600
601 if (release)
602 (*release) (info);
603
604 __CFBitClear(stream->flags, CALLING_CLIENT);
605 }
606
607 static void _cfstream_solo_signalEventSync(void* info)
608 {
609 CFTypeID typeID = CFGetTypeID((CFTypeRef) info);
610
611 if (typeID != CFReadStreamGetTypeID() && typeID != CFWriteStreamGetTypeID()) {
612 CFLog(__kCFLogAssertion, CFSTR("Expected an read or write stream for %p"), info);
613 #if defined(DEBUG)
614 abort();
615 #endif
616 } else {
617 struct _CFStream* stream = (struct _CFStream*) info;
618 CFOptionFlags whatToSignal = stream->client->whatToSignal;
619 stream->client->whatToSignal = 0;
620
621 /* Since the array version holds a retain, we do it here as well, as opposed to taking a second retain in the client callback */
622 CFRetain(stream);
623 _signalEventSync(stream, whatToSignal);
624 CFRelease(stream);
625 }
626 }
627
628 static void _cfstream_shared_signalEventSync(void* info)
629 {
630 CFTypeID typeID = CFGetTypeID((CFTypeRef) info);
631
632 if (typeID != CFArrayGetTypeID()) {
633 CFLog(__kCFLogAssertion, CFSTR("Expected an array for %p"), info);
634 #if defined(DEBUG)
635 abort();
636 #endif
637 } else {
638 CFMutableArrayRef list = (CFMutableArrayRef) info;
639 CFIndex c, i;
640 CFOptionFlags whatToSignal = 0;
641 struct _CFStream* stream = NULL;
642
643 __CFSpinLock(&sSourceLock);
644
645 /* Looks like, we grab the first stream that wants an event... */
646 /* Note that I grab an extra retain when I pull out the stream here... */
647 c = CFArrayGetCount(list);
648 for (i = 0; i < c; i++) {
649 struct _CFStream* s = (struct _CFStream*)CFArrayGetValueAtIndex(list, i);
650
651 if (s->client->whatToSignal) {
652 stream = s;
653 CFRetain(stream);
654 whatToSignal = stream->client->whatToSignal;
655 s->client->whatToSignal = 0;
656 break;
657 }
658 }
659
660 /* And then we also signal any other streams in this array so that we get them next go? */
661 for (; i < c; i++) {
662 struct _CFStream* s = (struct _CFStream*)CFArrayGetValueAtIndex(list, i);
663 if (s->client->whatToSignal) {
664 CFRunLoopSourceRef source = _CFStreamCopySource(s);
665 if (source) {
666 CFRunLoopSourceSignal(source);
667 CFRelease(source);
668 }
669 break;
670 }
671 }
672
673 __CFSpinUnlock(&sSourceLock);
674
675 /* We're sitting here now, possibly with a stream that needs to be processed by the common routine */
676 if (stream) {
677 _signalEventSync(stream, whatToSignal);
678
679 /* Lose our extra retain */
680 CFRelease(stream);
681 }
682 }
683 }
684
685 /* This routine is to be considered unsafe... */
686 static CFArrayRef _CFStreamGetRunLoopsAndModes(struct _CFStream *stream)
687 {
688 CFArrayRef result = NULL;
689 if (stream && stream->client) {
690 _CFStreamLock(stream);
691 struct CFStreamAux* aux = _CFStreamGetAuxRecord(stream);
692 if (aux->previousRunloopsAndModes) {
693 CFRelease(aux->previousRunloopsAndModes);
694 aux->previousRunloopsAndModes = NULL;
695 }
696 if (stream->client->runLoopsAndModes) {
697 aux->previousRunloopsAndModes = CFArrayCreateCopy(CFGetAllocator(stream), stream->client->runLoopsAndModes);
698 }
699 result = aux->previousRunloopsAndModes;
700 checkRLMArray(result);
701 _CFStreamUnlock(stream);
702 }
703 return result;
704 }
705
706 static CFArrayRef _CFStreamCopyRunLoopsAndModes(struct _CFStream *stream)
707 {
708 CFArrayRef result = NULL;
709 if (stream && stream->client) {
710 _CFStreamLock(stream);
711 if (stream->client->runLoopsAndModes) {
712 result = CFArrayCreateCopy(CFGetAllocator(stream), stream->client->runLoopsAndModes);
713 }
714 checkRLMArray(result);
715 _CFStreamUnlock(stream);
716 }
717 return result;
718 }
719
720 static void _wakeUpRunLoop(struct _CFStream *stream) {
721 CFArrayRef rlArray = _CFStreamCopyRunLoopsAndModes(stream);
722 if (rlArray) {
723 CFIndex cnt = CFArrayGetCount(rlArray);
724 CFRunLoopRef rl = NULL;
725
726 if (cnt == 2) {
727 rl = (CFRunLoopRef)CFArrayGetValueAtIndex(rlArray, 0);
728 } else if (cnt > 2) {
729 CFIndex idx;
730 rl = (CFRunLoopRef)CFArrayGetValueAtIndex(rlArray, 0);
731 for (idx = 2; NULL != rl && idx < cnt; idx+=2) {
732 CFRunLoopRef value = (CFRunLoopRef)CFArrayGetValueAtIndex(rlArray, idx);
733 if (value != rl) rl = NULL;
734 }
735 if (NULL == rl) { /* more than one different rl, so we must pick one */
736 for (idx = 0; idx < cnt; idx+=2) {
737 CFRunLoopRef value = (CFRunLoopRef)CFArrayGetValueAtIndex(rlArray, idx);
738 CFStringRef currentMode = CFRunLoopCopyCurrentMode(value);
739 if (NULL != currentMode && CFEqual(currentMode, CFArrayGetValueAtIndex(rlArray, idx+1)) && CFRunLoopIsWaiting(value)) {
740 CFRelease(currentMode);
741 rl = value;
742 break;
743 }
744 if (NULL != currentMode) CFRelease(currentMode);
745 }
746 if (NULL == rl) { /* didn't choose one above, so choose first */
747 rl = (CFRunLoopRef)CFArrayGetValueAtIndex(rlArray, 0);
748 }
749 }
750 }
751 if (NULL != rl && CFRunLoopIsWaiting(rl))
752 CFRunLoopWakeUp(rl);
753 CFRelease(rlArray);
754 }
755 }
756
757 __private_extern__ void _CFStreamSignalEvent(struct _CFStream *stream, CFStreamEventType event, CFErrorRef error, Boolean synchronousAllowed) {
758 // Update our internal status; we must use the primitive __CFStreamGetStatus(), because CFStreamGetStatus() calls us, and we can end up in an infinite loop.
759 CFStreamStatus status = __CFStreamGetStatus(stream);
760
761 // Sanity check the event
762 if (status == kCFStreamStatusNotOpen) {
763 // No events allowed; this is almost certainly a bug in the stream's implementation
764 CFLog(__kCFLogAssertion, CFSTR("Stream %p is sending an event before being opened"), stream);
765 event = 0;
766 } else if (status == kCFStreamStatusClosed || status == kCFStreamStatusError) {
767 // no further events are allowed
768 event = 0;
769 } else if (status == kCFStreamStatusAtEnd) {
770 // Only error events are allowed
771 event &= kCFStreamEventErrorOccurred;
772 } else if (status != kCFStreamStatusOpening) {
773 // cannot send open completed; that happened already
774 event &= ~kCFStreamEventOpenCompleted;
775 }
776
777 // Change status if appropriate
778 if (event & kCFStreamEventOpenCompleted && status == kCFStreamStatusOpening) {
779 _CFStreamSetStatusCode(stream, kCFStreamStatusOpen);
780 }
781 if (event & kCFStreamEventEndEncountered && status < kCFStreamStatusAtEnd) {
782 _CFStreamSetStatusCode(stream, kCFStreamStatusAtEnd);
783 }
784 if (event & kCFStreamEventErrorOccurred) {
785 if (_CFStreamGetCallBackPtr(stream)->version < 2) {
786 _CFStreamSetStreamError(stream, (CFStreamError *)error);
787 } else {
788 CFAssert(error, __kCFLogAssertion, "CFStream: kCFStreamEventErrorOccurred signalled, but error is NULL!");
789 CFRetain(error);
790 if (stream->error) CFRelease(stream->error);
791 stream->error = error;
792 }
793 _CFStreamSetStatusCode(stream, kCFStreamStatusError);
794 }
795
796 // Now signal any pertinent event
797 if (stream->client && (stream->client->when & event) != 0) {
798 CFRunLoopSourceRef source = _CFStreamCopySource(stream);
799
800 if (source) {
801 Boolean signalNow = FALSE;
802
803 stream->client->whatToSignal |= event;
804
805 if (synchronousAllowed && !__CFBitIsSet(stream->flags, CALLING_CLIENT)) {
806
807 CFRunLoopRef rl = CFRunLoopGetCurrent();
808 CFStringRef mode = CFRunLoopCopyCurrentMode(rl);
809
810 if (mode) {
811 if (CFRunLoopContainsSource(rl, source, mode))
812 signalNow = TRUE;
813 }
814 if (mode)
815 CFRelease(mode);
816 }
817
818 if (signalNow) {
819 // Can call out safely right now
820 _cfstream_solo_signalEventSync(stream);
821 } else {
822 // Schedule for later delivery
823 if (source) {
824 CFRunLoopSourceSignal(source);
825 }
826 _wakeUpRunLoop(stream);
827 }
828
829 CFRelease(source);
830 }
831 }
832 }
833
834 __private_extern__ CFStreamStatus _CFStreamGetStatus(struct _CFStream *stream) {
835 CFStreamStatus status = __CFStreamGetStatus(stream);
836 // Status code just represents the value when last we checked; if we were in the middle of doing work at that time, we need to find out if the work has completed, now. If we find out about a status change, we need to inform the client as well, so we call _CFStreamSignalEvent. This will take care of updating our internal status correctly, too.
837 __CFBitSet(stream->flags, CALLING_CLIENT);
838 if (status == kCFStreamStatusOpening) {
839 const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
840 if (cb->openCompleted) {
841 Boolean isComplete;
842 if (cb->version < 2) {
843 CFStreamError err = {0, 0};
844 isComplete = ((_CFStreamCBOpenCompletedV1)(cb->openCompleted))(stream, &err, _CFStreamGetInfoPointer(stream));
845 if (err.error != 0) _CFStreamSetStreamError(stream, &err);
846 } else {
847 isComplete = cb->openCompleted(stream, &(stream->error), _CFStreamGetInfoPointer(stream));
848 }
849 if (isComplete) {
850 if (!stream->error) {
851 status = kCFStreamStatusOpen;
852 } else {
853 status = kCFStreamStatusError;
854 }
855 _CFStreamSetStatusCode(stream, status);
856 if (status == kCFStreamStatusOpen) {
857 _CFStreamScheduleEvent(stream, kCFStreamEventOpenCompleted);
858 } else {
859 _CFStreamScheduleEvent(stream, kCFStreamEventErrorOccurred);
860 }
861 }
862 }
863 }
864 __CFBitClear(stream->flags, CALLING_CLIENT);
865 return status;
866 }
867
868 CF_EXPORT CFStreamStatus CFReadStreamGetStatus(CFReadStreamRef stream) {
869 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID, CFStreamStatus, (NSInputStream *)stream, streamStatus);
870 return _CFStreamGetStatus((struct _CFStream *)stream);
871 }
872
873 CF_EXPORT CFStreamStatus CFWriteStreamGetStatus(CFWriteStreamRef stream) {
874 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID, CFStreamStatus, (NSOutputStream *)stream, streamStatus);
875 return _CFStreamGetStatus((struct _CFStream *)stream);
876 }
877
878 static CFStreamError _CFStreamGetStreamError(struct _CFStream *stream) {
879 CFStreamError result;
880 if (!stream->error) {
881 result.error = 0;
882 result.domain = 0;
883 } else if (_CFStreamGetCallBackPtr(stream)->version < 2) {
884 CFStreamError *streamError = (CFStreamError *)(stream->error);
885 result.error = streamError->error;
886 result.domain = streamError->domain;
887 } else {
888 result = _CFStreamErrorFromError(stream->error);
889 }
890 return result;
891 }
892
893 CF_EXPORT CFStreamError CFReadStreamGetError(CFReadStreamRef stream) {
894 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID, CFStreamError, (NSInputStream *)stream, _cfStreamError);
895 return _CFStreamGetStreamError((struct _CFStream *)stream);
896 }
897
898 CF_EXPORT CFStreamError CFWriteStreamGetError(CFWriteStreamRef stream) {
899 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID, CFStreamError, (NSOutputStream *)stream, _cfStreamError);
900 return _CFStreamGetStreamError((struct _CFStream *)stream);
901 }
902
903 static CFErrorRef _CFStreamCopyError(struct _CFStream *stream) {
904 if (!stream->error) {
905 return NULL;
906 } else if (_CFStreamGetCallBackPtr(stream)->version < 2) {
907 return _CFErrorFromStreamError(CFGetAllocator(stream), (CFStreamError *)(stream->error));
908 } else {
909 CFRetain(stream->error);
910 return stream->error;
911 }
912 }
913
914 CF_EXPORT CFErrorRef CFReadStreamCopyError(CFReadStreamRef stream) {
915 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID, CFErrorRef, (NSInputStream *)stream, streamError);
916 return _CFStreamCopyError((struct _CFStream *)stream);
917 }
918
919 CF_EXPORT CFErrorRef CFWriteStreamCopyError(CFWriteStreamRef stream) {
920 return _CFStreamCopyError((struct _CFStream *)stream);
921 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID, CFErrorRef, (NSOutputStream *)stream, streamError);
922 }
923
924 __private_extern__ Boolean _CFStreamOpen(struct _CFStream *stream) {
925 const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
926 Boolean success, openComplete;
927 if (_CFStreamGetStatus(stream) != kCFStreamStatusNotOpen) {
928 return FALSE;
929 }
930 __CFBitSet(stream->flags, CALLING_CLIENT);
931 _CFStreamSetStatusCode(stream, kCFStreamStatusOpening);
932 if (cb->open) {
933 if (cb->version < 2) {
934 CFStreamError err = {0, 0};
935 success = ((_CFStreamCBOpenV1)(cb->open))(stream, &err, &openComplete, _CFStreamGetInfoPointer(stream));
936 if (err.error != 0) _CFStreamSetStreamError(stream, &err);
937 } else {
938 success = cb->open(stream, &(stream->error), &openComplete, _CFStreamGetInfoPointer(stream));
939 }
940 } else {
941 success = TRUE;
942 openComplete = TRUE;
943 }
944 if (openComplete) {
945 if (success) {
946 // 2957690 - Guard against the possibility that the stream has already signalled itself in to a later state (like AtEnd)
947 if (__CFStreamGetStatus(stream) == kCFStreamStatusOpening) {
948 _CFStreamSetStatusCode(stream, kCFStreamStatusOpen);
949 }
950 _CFStreamScheduleEvent(stream, kCFStreamEventOpenCompleted);
951 } else {
952 #if DEPLOYMENT_TARGET_WINDOWS
953 _CFStreamClose(stream);
954 #endif
955 _CFStreamSetStatusCode(stream, kCFStreamStatusError);
956 _CFStreamScheduleEvent(stream, kCFStreamEventErrorOccurred);
957 }
958 }
959 __CFBitClear(stream->flags, CALLING_CLIENT);
960 return success;
961 }
962
963 CF_EXPORT Boolean CFReadStreamOpen(CFReadStreamRef stream) {
964 if(CF_IS_OBJC(__kCFReadStreamTypeID, stream)) {
965 (void)CF_OBJC_CALLV((NSInputStream *)stream, open);
966 return TRUE;
967 }
968 return _CFStreamOpen((struct _CFStream *)stream);
969 }
970
971 CF_EXPORT Boolean CFWriteStreamOpen(CFWriteStreamRef stream) {
972 if(CF_IS_OBJC(__kCFWriteStreamTypeID, stream)) {
973 (void)CF_OBJC_CALLV((NSOutputStream *)stream, open);
974 return TRUE;
975 }
976 return _CFStreamOpen((struct _CFStream *)stream);
977 }
978
979 CF_EXPORT void CFReadStreamClose(CFReadStreamRef stream) {
980 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID, void, (NSInputStream *)stream, close);
981 _CFStreamClose((struct _CFStream *)stream);
982 }
983
984 CF_EXPORT void CFWriteStreamClose(CFWriteStreamRef stream) {
985 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID, void, (NSOutputStream *)stream, close);
986 _CFStreamClose((struct _CFStream *)stream);
987 }
988
989 CF_EXPORT Boolean CFReadStreamHasBytesAvailable(CFReadStreamRef readStream) {
990 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID, Boolean, (NSInputStream *)readStream, hasBytesAvailable);
991 struct _CFStream *stream = (struct _CFStream *)readStream;
992 CFStreamStatus status = _CFStreamGetStatus(stream);
993 const struct _CFStreamCallBacks *cb;
994 if (status != kCFStreamStatusOpen && status != kCFStreamStatusReading) {
995 return FALSE;
996 }
997 cb = _CFStreamGetCallBackPtr(stream);
998 if (cb->canRead == NULL) {
999 return TRUE; // No way to know without trying....
1000 } else {
1001 Boolean result;
1002 __CFBitSet(stream->flags, CALLING_CLIENT);
1003 if (cb->version < 2) {
1004 result = ((_CFStreamCBCanReadV1)(cb->canRead))((CFReadStreamRef)stream, _CFStreamGetInfoPointer(stream));
1005 } else {
1006 result = cb->canRead((CFReadStreamRef)stream, &(stream->error), _CFStreamGetInfoPointer(stream));
1007 if (stream->error) {
1008 _CFStreamSetStatusCode(stream, kCFStreamStatusError);
1009 _CFStreamScheduleEvent(stream, kCFStreamEventErrorOccurred);
1010 }
1011 }
1012 __CFBitClear(stream->flags, CALLING_CLIENT);
1013 return result;
1014 }
1015 }
1016
1017 static void waitForOpen(struct _CFStream *stream);
1018 CFIndex CFReadStreamRead(CFReadStreamRef readStream, UInt8 *buffer, CFIndex bufferLength) {
1019 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID, CFIndex, (NSInputStream *)readStream, read:(uint8_t *)buffer maxLength:(NSUInteger)bufferLength);
1020 struct _CFStream *stream = (struct _CFStream *)readStream;
1021 CFStreamStatus status = _CFStreamGetStatus(stream);
1022 const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
1023 if (status == kCFStreamStatusOpening) {
1024 __CFBitSet(stream->flags, CALLING_CLIENT);
1025 waitForOpen(stream);
1026 __CFBitClear(stream->flags, CALLING_CLIENT);
1027 status = _CFStreamGetStatus(stream);
1028 }
1029
1030 if (status != kCFStreamStatusOpen && status != kCFStreamStatusReading && status != kCFStreamStatusAtEnd) {
1031 return -1;
1032 } else if (status == kCFStreamStatusAtEnd) {
1033 return 0;
1034 } else {
1035 Boolean atEOF;
1036 CFIndex bytesRead;
1037 __CFBitSet(stream->flags, CALLING_CLIENT);
1038 if (stream->client) {
1039 stream->client->whatToSignal &= ~kCFStreamEventHasBytesAvailable;
1040 }
1041 _CFStreamSetStatusCode(stream, kCFStreamStatusReading);
1042 if (cb->version < 2) {
1043 CFStreamError err = {0, 0};
1044 bytesRead = ((_CFStreamCBReadV1)(cb->read))((CFReadStreamRef)stream, buffer, bufferLength, &err, &atEOF, _CFStreamGetInfoPointer(stream));
1045 if (err.error != 0) _CFStreamSetStreamError(stream, &err);
1046 } else {
1047 bytesRead = cb->read((CFReadStreamRef)stream, buffer, bufferLength, &(stream->error), &atEOF, _CFStreamGetInfoPointer(stream));
1048 }
1049 if (stream->error) {
1050 bytesRead = -1;
1051 _CFStreamSetStatusCode(stream, kCFStreamStatusError);
1052 _CFStreamScheduleEvent(stream, kCFStreamEventErrorOccurred);
1053 } else if (atEOF) {
1054 _CFStreamSetStatusCode(stream, kCFStreamStatusAtEnd);
1055 _CFStreamScheduleEvent(stream, kCFStreamEventEndEncountered);
1056 } else {
1057 _CFStreamSetStatusCode(stream, kCFStreamStatusOpen);
1058 }
1059 __CFBitClear(stream->flags, CALLING_CLIENT);
1060 return bytesRead;
1061 }
1062 }
1063
1064 CF_EXPORT const UInt8 *CFReadStreamGetBuffer(CFReadStreamRef readStream, CFIndex maxBytesToRead, CFIndex *numBytesRead) {
1065 if (CF_IS_OBJC(__kCFReadStreamTypeID, readStream)) {
1066 uint8_t *bufPtr = NULL;
1067 Boolean gotBytes = (Boolean) CF_OBJC_CALLV((NSInputStream *)readStream, getBuffer:&bufPtr length:(NSUInteger *)numBytesRead);
1068 if(gotBytes) {
1069 return (const UInt8 *)bufPtr;
1070 } else {
1071 return NULL;
1072 }
1073 }
1074 struct _CFStream *stream = (struct _CFStream *)readStream;
1075 CFStreamStatus status = _CFStreamGetStatus(stream);
1076 const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
1077 const UInt8 *buffer;
1078 if (status == kCFStreamStatusOpening) {
1079 __CFBitSet(stream->flags, CALLING_CLIENT);
1080 waitForOpen(stream);
1081 __CFBitClear(stream->flags, CALLING_CLIENT);
1082 status = _CFStreamGetStatus(stream);
1083 }
1084 if (status != kCFStreamStatusOpen && status != kCFStreamStatusReading && status != kCFStreamStatusAtEnd) {
1085 *numBytesRead = -1;
1086 buffer = NULL;
1087 } else if (status == kCFStreamStatusAtEnd || cb->getBuffer == NULL) {
1088 *numBytesRead = 0;
1089 buffer = NULL;
1090 } else {
1091 Boolean atEOF;
1092 Boolean hadBytes = stream->client && (stream->client->whatToSignal & kCFStreamEventHasBytesAvailable);
1093 __CFBitSet(stream->flags, CALLING_CLIENT);
1094 if (hadBytes) {
1095 stream->client->whatToSignal &= ~kCFStreamEventHasBytesAvailable;
1096 }
1097 _CFStreamSetStatusCode(stream, kCFStreamStatusReading);
1098 if (cb->version < 2) {
1099 CFStreamError err = {0, 0};
1100 buffer = ((_CFStreamCBGetBufferV1)(cb->getBuffer))((CFReadStreamRef)stream, maxBytesToRead, numBytesRead, &err, &atEOF, _CFStreamGetInfoPointer(stream));
1101 if (err.error != 0) _CFStreamSetStreamError(stream, &err);
1102 } else {
1103 buffer = cb->getBuffer((CFReadStreamRef)stream, maxBytesToRead, numBytesRead, &(stream->error), &atEOF, _CFStreamGetInfoPointer(stream));
1104 }
1105 if (stream->error) {
1106 *numBytesRead = -1;
1107 _CFStreamSetStatusCode(stream, kCFStreamStatusError);
1108 buffer = NULL;
1109 _CFStreamScheduleEvent(stream, kCFStreamEventErrorOccurred);
1110 } else if (atEOF) {
1111 _CFStreamSetStatusCode(stream, kCFStreamStatusAtEnd);
1112 _CFStreamScheduleEvent(stream, kCFStreamEventEndEncountered);
1113 } else {
1114 if (!buffer && hadBytes) {
1115 stream->client->whatToSignal |= kCFStreamEventHasBytesAvailable;
1116 }
1117 _CFStreamSetStatusCode(stream, kCFStreamStatusOpen);
1118 }
1119 __CFBitClear(stream->flags, CALLING_CLIENT);
1120 }
1121 return buffer;
1122 }
1123
1124 CF_EXPORT Boolean CFWriteStreamCanAcceptBytes(CFWriteStreamRef writeStream) {
1125 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID, Boolean, (NSOutputStream *)writeStream, hasSpaceAvailable);
1126 struct _CFStream *stream = (struct _CFStream *)writeStream;
1127 CFStreamStatus status = _CFStreamGetStatus(stream);
1128 const struct _CFStreamCallBacks *cb;
1129 if (status != kCFStreamStatusOpen && status != kCFStreamStatusWriting) {
1130 return FALSE;
1131 }
1132 cb = _CFStreamGetCallBackPtr(stream);
1133 if (cb->canWrite == NULL) {
1134 return TRUE; // No way to know without trying....
1135 } else {
1136 Boolean result;
1137 __CFBitSet(stream->flags, CALLING_CLIENT);
1138 if (cb->version < 2) {
1139 result = ((_CFStreamCBCanWriteV1)(cb->canWrite))((CFWriteStreamRef)stream, _CFStreamGetInfoPointer(stream));
1140 } else {
1141 result = cb->canWrite((CFWriteStreamRef)stream, &(stream->error), _CFStreamGetInfoPointer(stream));
1142 if (stream->error) {
1143 _CFStreamSetStatusCode(stream, kCFStreamStatusError);
1144 _CFStreamScheduleEvent(stream, kCFStreamEventErrorOccurred);
1145 }
1146 }
1147 __CFBitClear(stream->flags, CALLING_CLIENT);
1148 return result;
1149 }
1150 }
1151
1152 CF_EXPORT CFIndex CFWriteStreamWrite(CFWriteStreamRef writeStream, const UInt8 *buffer, CFIndex bufferLength) {
1153 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID, CFIndex, (NSOutputStream *)writeStream, write:(const uint8_t *)buffer maxLength:(NSUInteger)bufferLength);
1154 struct _CFStream *stream = (struct _CFStream *)writeStream;
1155 CFStreamStatus status = _CFStreamGetStatus(stream);
1156 const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
1157 if (status == kCFStreamStatusOpening) {
1158 __CFBitSet(stream->flags, CALLING_CLIENT);
1159 waitForOpen(stream);
1160 __CFBitClear(stream->flags, CALLING_CLIENT);
1161 status = _CFStreamGetStatus(stream);
1162 }
1163 if (status != kCFStreamStatusOpen && status != kCFStreamStatusWriting) {
1164 return -1;
1165 } else {
1166 CFIndex result;
1167 __CFBitSet(stream->flags, CALLING_CLIENT);
1168 _CFStreamSetStatusCode(stream, kCFStreamStatusWriting);
1169 if (stream->client) {
1170 stream->client->whatToSignal &= ~kCFStreamEventCanAcceptBytes;
1171 }
1172 if (cb->version < 2) {
1173 CFStreamError err = {0, 0};
1174 result = ((_CFStreamCBWriteV1)(cb->write))((CFWriteStreamRef)stream, buffer, bufferLength, &err, _CFStreamGetInfoPointer(stream));
1175 if (err.error) _CFStreamSetStreamError(stream, &err);
1176 } else {
1177 result = cb->write((CFWriteStreamRef)stream, buffer, bufferLength, &(stream->error), _CFStreamGetInfoPointer(stream));
1178 }
1179 if (stream->error) {
1180 _CFStreamSetStatusCode(stream, kCFStreamStatusError);
1181 _CFStreamScheduleEvent(stream, kCFStreamEventErrorOccurred);
1182 } else if (result == 0) {
1183 _CFStreamSetStatusCode(stream, kCFStreamStatusAtEnd);
1184 _CFStreamScheduleEvent(stream, kCFStreamEventEndEncountered);
1185 } else {
1186 _CFStreamSetStatusCode(stream, kCFStreamStatusOpen);
1187 }
1188 __CFBitClear(stream->flags, CALLING_CLIENT);
1189 return result;
1190 }
1191 }
1192
1193 __private_extern__ CFTypeRef _CFStreamCopyProperty(struct _CFStream *stream, CFStringRef propertyName) {
1194 const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
1195 if (cb->copyProperty == NULL) {
1196 return NULL;
1197 } else {
1198 CFTypeRef result;
1199 __CFBitSet(stream->flags, CALLING_CLIENT);
1200 result = cb->copyProperty(stream, propertyName, _CFStreamGetInfoPointer(stream));
1201 __CFBitClear(stream->flags, CALLING_CLIENT);
1202 return result;
1203 }
1204 }
1205
1206 CF_EXPORT CFTypeRef CFReadStreamCopyProperty(CFReadStreamRef stream, CFStringRef propertyName) {
1207 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID, CFTypeRef, (NSInputStream *)stream, propertyForKey:(NSString *)propertyName);
1208 return _CFStreamCopyProperty((struct _CFStream *)stream, propertyName);
1209 }
1210
1211 CF_EXPORT CFTypeRef CFWriteStreamCopyProperty(CFWriteStreamRef stream, CFStringRef propertyName) {
1212 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID, CFTypeRef, (NSOutputStream *)stream, propertyForKey:(NSString *)propertyName);
1213 return _CFStreamCopyProperty((struct _CFStream *)stream, propertyName);
1214 }
1215
1216 __private_extern__ Boolean _CFStreamSetProperty(struct _CFStream *stream, CFStringRef prop, CFTypeRef val) {
1217 const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
1218 if (cb->setProperty == NULL) {
1219 return FALSE;
1220 } else {
1221 Boolean result;
1222 __CFBitSet(stream->flags, CALLING_CLIENT);
1223 result = cb->setProperty(stream, prop, val, _CFStreamGetInfoPointer(stream));
1224 __CFBitClear(stream->flags, CALLING_CLIENT);
1225 return result;
1226 }
1227 }
1228
1229 CF_EXPORT
1230 Boolean CFReadStreamSetProperty(CFReadStreamRef stream, CFStringRef propertyName, CFTypeRef propertyValue) {
1231 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID, Boolean, (NSInputStream *)stream, setProperty:(id)propertyValue forKey:(NSString *)propertyName);
1232 return _CFStreamSetProperty((struct _CFStream *)stream, propertyName, propertyValue);
1233 }
1234
1235 CF_EXPORT
1236 Boolean CFWriteStreamSetProperty(CFWriteStreamRef stream, CFStringRef propertyName, CFTypeRef propertyValue) {
1237 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID, Boolean, (NSOutputStream *)stream, setProperty:(id)propertyValue forKey:(NSString *)propertyName);
1238 return _CFStreamSetProperty((struct _CFStream *)stream, propertyName, propertyValue);
1239 }
1240
1241 static void _initializeClient(struct _CFStream *stream) {
1242 const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
1243 if (!cb->schedule) return; // Do we wish to allow this?
1244 stream->client = (struct _CFStreamClient *)CFAllocatorAllocate(CFGetAllocator(stream), sizeof(struct _CFStreamClient), 0);
1245 memset(stream->client, 0, sizeof(struct _CFStreamClient));
1246 }
1247
1248 /* If we add a setClient callback to the concrete stream callbacks, we must set/clear CALLING_CLIENT around it */
1249 __private_extern__ Boolean _CFStreamSetClient(struct _CFStream *stream, CFOptionFlags streamEvents, void (*clientCB)(struct _CFStream *, CFStreamEventType, void *), CFStreamClientContext *clientCallBackContext) {
1250
1251 Boolean removingClient = (streamEvents == kCFStreamEventNone || clientCB == NULL || clientCallBackContext == NULL);
1252
1253 if (removingClient) {
1254 clientCB = NULL;
1255 streamEvents = kCFStreamEventNone;
1256 clientCallBackContext = NULL;
1257 }
1258 if (!stream->client) {
1259 if (removingClient) {
1260 // We have no client now, and we've been asked to add none???
1261 return TRUE;
1262 }
1263 _initializeClient(stream);
1264 if (!stream->client) {
1265 // Asynch not supported
1266 return FALSE;
1267 }
1268 }
1269 if (stream->client->cb && stream->client->cbContext.release) {
1270 stream->client->cbContext.release(stream->client->cbContext.info);
1271 }
1272 stream->client->cb = clientCB;
1273 if (clientCallBackContext) {
1274 stream->client->cbContext.version = clientCallBackContext->version;
1275 stream->client->cbContext.retain = clientCallBackContext->retain;
1276 stream->client->cbContext.release = clientCallBackContext->release;
1277 stream->client->cbContext.copyDescription = clientCallBackContext->copyDescription;
1278 stream->client->cbContext.info = (clientCallBackContext->retain && clientCallBackContext->info) ? clientCallBackContext->retain(clientCallBackContext->info) : clientCallBackContext->info;
1279 } else {
1280 stream->client->cbContext.retain = NULL;
1281 stream->client->cbContext.release = NULL;
1282 stream->client->cbContext.copyDescription = NULL;
1283 stream->client->cbContext.info = NULL;
1284 }
1285 if (stream->client->when != streamEvents) {
1286 const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
1287 stream->client->when = streamEvents;
1288 if (cb->requestEvents) {
1289 cb->requestEvents(stream, streamEvents, _CFStreamGetInfoPointer(stream));
1290 }
1291 }
1292 return TRUE;
1293 }
1294
1295 CF_EXPORT Boolean CFReadStreamSetClient(CFReadStreamRef readStream, CFOptionFlags streamEvents, CFReadStreamClientCallBack clientCB, CFStreamClientContext *clientContext) {
1296 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID, Boolean, (NSInputStream *)readStream, _setCFClientFlags:streamEvents callback:clientCB context:clientContext);
1297 streamEvents &= ~kCFStreamEventCanAcceptBytes;
1298 return _CFStreamSetClient((struct _CFStream *)readStream, streamEvents, (void (*)(struct _CFStream *, CFStreamEventType, void *))clientCB, clientContext);
1299 }
1300
1301 CF_EXPORT Boolean CFWriteStreamSetClient(CFWriteStreamRef writeStream, CFOptionFlags streamEvents, CFWriteStreamClientCallBack clientCB, CFStreamClientContext *clientContext) {
1302 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID, Boolean, (NSOutputStream *)writeStream, _setCFClientFlags:streamEvents callback:clientCB context:clientContext);
1303 streamEvents &= ~kCFStreamEventHasBytesAvailable;
1304 return _CFStreamSetClient((struct _CFStream *)writeStream, streamEvents, (void (*)(struct _CFStream *, CFStreamEventType, void *))clientCB, clientContext);
1305 }
1306
1307 CF_INLINE void *_CFStreamGetClient(struct _CFStream *stream) {
1308 if (stream->client) return stream->client->cbContext.info;
1309 else return NULL;
1310 }
1311
1312 CF_EXPORT void *_CFReadStreamGetClient(CFReadStreamRef readStream) {
1313 return _CFStreamGetClient((struct _CFStream *)readStream);
1314 }
1315
1316 CF_EXPORT void *_CFWriteStreamGetClient(CFWriteStreamRef writeStream) {
1317 return _CFStreamGetClient((struct _CFStream *)writeStream);
1318 }
1319
1320
1321 __private_extern__ void _CFStreamScheduleWithRunLoop(struct _CFStream *stream, CFRunLoopRef runLoop, CFStringRef runLoopMode) {
1322 const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
1323
1324 if (! stream->client) {
1325 _initializeClient(stream);
1326 if (!stream->client) return; // we don't support asynch.
1327 }
1328
1329 if (! stream->client->rlSource) {
1330 /* No source, so we join the shared source group */
1331 CFTypeRef a[] = { runLoop, runLoopMode };
1332
1333 CFArrayRef runLoopAndSourceKey = CFArrayCreate(kCFAllocatorSystemDefault, a, sizeof(a) / sizeof(a[0]), &kCFTypeArrayCallBacks);
1334
1335 __CFSpinLock(&sSourceLock);
1336
1337 if (!sSharedSources)
1338 sSharedSources = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1339
1340 CFMutableArrayRef listOfStreamsSharingASource = (CFMutableArrayRef)CFDictionaryGetValue(sSharedSources, runLoopAndSourceKey);
1341 if (listOfStreamsSharingASource) {
1342 struct _CFStream* aStream = (struct _CFStream*) CFArrayGetValueAtIndex(listOfStreamsSharingASource, 0);
1343 CFRunLoopSourceRef source = _CFStreamCopySource(aStream);
1344 if (source) {
1345 _CFStreamSetSource(stream, source, FALSE);
1346 CFRelease(source);
1347 }
1348 CFRetain(listOfStreamsSharingASource);
1349 }
1350 else {
1351 CFRunLoopSourceContext ctxt = {
1352 0,
1353 NULL,
1354 CFRetain,
1355 CFRelease,
1356 (CFStringRef(*)(const void *))CFCopyDescription,
1357 NULL,
1358 NULL,
1359 NULL,
1360 NULL,
1361 (void(*)(void *))_cfstream_shared_signalEventSync
1362 };
1363
1364 listOfStreamsSharingASource = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
1365 CFDictionaryAddValue(sSharedSources, runLoopAndSourceKey, listOfStreamsSharingASource);
1366
1367 ctxt.info = listOfStreamsSharingASource;
1368
1369 CFRunLoopSourceRef source = CFRunLoopSourceCreate(kCFAllocatorSystemDefault, 0, &ctxt);
1370 _CFStreamSetSource(stream, source, FALSE);
1371 CFRunLoopAddSource(runLoop, source, runLoopMode);
1372 CFRelease(source);
1373 }
1374
1375 CFArrayAppendValue(listOfStreamsSharingASource, stream);
1376 CFDictionaryAddValue(sSharedSources, stream, runLoopAndSourceKey);
1377
1378 CFRelease(runLoopAndSourceKey);
1379 CFRelease(listOfStreamsSharingASource);
1380
1381 __CFBitSet(stream->flags, SHARED_SOURCE);
1382
1383 __CFSpinUnlock(&sSourceLock);
1384 }
1385 else if (__CFBitIsSet(stream->flags, SHARED_SOURCE)) {
1386 /* We were sharing, but now we'll get our own source */
1387
1388 CFArrayRef runLoopAndSourceKey;
1389 CFMutableArrayRef listOfStreamsSharingASource;
1390 CFIndex count, i;
1391
1392 CFAllocatorRef alloc = CFGetAllocator(stream);
1393 CFRunLoopSourceContext ctxt = {
1394 0,
1395 (void *)stream,
1396 NULL, // Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop
1397 NULL, // Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop
1398 (CFStringRef(*)(const void *))CFCopyDescription,
1399 NULL,
1400 NULL,
1401 NULL,
1402 NULL,
1403 (void(*)(void *))_cfstream_solo_signalEventSync
1404 };
1405
1406 __CFSpinLock(&sSourceLock);
1407
1408 runLoopAndSourceKey = (CFArrayRef)CFRetain((CFTypeRef)CFDictionaryGetValue(sSharedSources, stream));
1409 listOfStreamsSharingASource = (CFMutableArrayRef)CFDictionaryGetValue(sSharedSources, runLoopAndSourceKey);
1410
1411 count = CFArrayGetCount(listOfStreamsSharingASource);
1412 i = CFArrayGetFirstIndexOfValue(listOfStreamsSharingASource, CFRangeMake(0, count), stream);
1413 if (i != kCFNotFound) {
1414 CFArrayRemoveValueAtIndex(listOfStreamsSharingASource, i);
1415 count--;
1416 }
1417
1418 if (count == 0) {
1419 CFRunLoopSourceRef source = _CFStreamCopySource(stream);
1420 if (source) {
1421 CFRunLoopRemoveSource((CFRunLoopRef)CFArrayGetValueAtIndex(runLoopAndSourceKey, 0), source, (CFStringRef)CFArrayGetValueAtIndex(runLoopAndSourceKey, 1));
1422 CFRelease(source);
1423 }
1424 CFDictionaryRemoveValue(sSharedSources, runLoopAndSourceKey);
1425 }
1426
1427 CFDictionaryRemoveValue(sSharedSources, stream);
1428
1429 _CFStreamSetSource(stream, NULL, count == 0);
1430
1431 __CFBitClear(stream->flags, SHARED_SOURCE);
1432
1433 __CFSpinUnlock(&sSourceLock);
1434
1435 CFRunLoopSourceRef source = CFRunLoopSourceCreate(alloc, 0, &ctxt);
1436 _CFStreamSetSource(stream, source, FALSE);
1437 CFRunLoopAddSource((CFRunLoopRef)CFArrayGetValueAtIndex(runLoopAndSourceKey, 0), source, (CFStringRef)CFArrayGetValueAtIndex(runLoopAndSourceKey, 1));
1438 CFRelease(runLoopAndSourceKey);
1439
1440 CFRunLoopAddSource(runLoop, source, runLoopMode);
1441
1442 CFRelease(source);
1443 } else {
1444 /* We're not sharing, so just add the source to the rl & mode */
1445 CFRunLoopSourceRef source = _CFStreamCopySource(stream);
1446 if (source) {
1447 CFRunLoopAddSource(runLoop, source, runLoopMode);
1448 CFRelease(source);
1449 }
1450 }
1451
1452 _CFStreamLock(stream);
1453 if (!stream->client->runLoopsAndModes) {
1454 stream->client->runLoopsAndModes = CFArrayCreateMutable(CFGetAllocator(stream), 0, &kCFTypeArrayCallBacks);
1455 }
1456 CFArrayAppendValue(stream->client->runLoopsAndModes, runLoop);
1457 CFArrayAppendValue(stream->client->runLoopsAndModes, runLoopMode);
1458 checkRLMArray(stream->client->runLoopsAndModes);
1459 _CFStreamUnlock(stream);
1460
1461 if (cb->schedule) {
1462 __CFBitSet(stream->flags, CALLING_CLIENT);
1463 cb->schedule(stream, runLoop, runLoopMode, _CFStreamGetInfoPointer(stream));
1464 __CFBitClear(stream->flags, CALLING_CLIENT);
1465 }
1466
1467 /*
1468 * If we've got events pending, we need to wake up and signal
1469 */
1470 if (stream->client && stream->client->whatToSignal != 0) {
1471 CFRunLoopSourceRef source = _CFStreamCopySource(stream);
1472 if (source) {
1473 CFRunLoopSourceSignal(source);
1474 CFRelease(source);
1475 _wakeUpRunLoop(stream);
1476 }
1477 }
1478 }
1479
1480 CF_EXPORT void CFReadStreamScheduleWithRunLoop(CFReadStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode) {
1481 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID, void, (NSInputStream *)stream, _scheduleInCFRunLoop:runLoop forMode:runLoopMode);
1482 _CFStreamScheduleWithRunLoop((struct _CFStream *)stream, runLoop, runLoopMode);
1483 }
1484
1485 CF_EXPORT void CFWriteStreamScheduleWithRunLoop(CFWriteStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode) {
1486 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID, void, (NSOutputStream *)stream, _scheduleInCFRunLoop:runLoop forMode:runLoopMode);
1487 _CFStreamScheduleWithRunLoop((struct _CFStream *)stream, runLoop, runLoopMode);
1488 }
1489
1490
1491 __private_extern__ void _CFStreamUnscheduleFromRunLoop(struct _CFStream *stream, CFRunLoopRef runLoop, CFStringRef runLoopMode) {
1492 const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
1493 if (!stream->client) return;
1494 if (!stream->client->rlSource) return;
1495
1496 if (!__CFBitIsSet(stream->flags, SHARED_SOURCE)) {
1497 CFRunLoopSourceRef source = _CFStreamCopySource(stream);
1498 if (source) {
1499 CFRunLoopRemoveSource(runLoop, source, runLoopMode);
1500 CFRelease(source);
1501 }
1502 } else {
1503 CFArrayRef runLoopAndSourceKey;
1504 CFMutableArrayRef list;
1505 CFIndex count, i;
1506
1507 __CFSpinLock(&sSourceLock);
1508
1509 runLoopAndSourceKey = (CFArrayRef)CFDictionaryGetValue(sSharedSources, stream);
1510 list = (CFMutableArrayRef)CFDictionaryGetValue(sSharedSources, runLoopAndSourceKey);
1511
1512 count = CFArrayGetCount(list);
1513 i = CFArrayGetFirstIndexOfValue(list, CFRangeMake(0, count), stream);
1514 if (i != kCFNotFound) {
1515 CFArrayRemoveValueAtIndex(list, i);
1516 count--;
1517 }
1518
1519 if (count == 0) {
1520 CFRunLoopSourceRef source = _CFStreamCopySource(stream);
1521 if (source) {
1522 CFRunLoopRemoveSource(runLoop, source, runLoopMode);
1523 CFRelease(source);
1524 }
1525 CFDictionaryRemoveValue(sSharedSources, runLoopAndSourceKey);
1526 }
1527
1528 CFDictionaryRemoveValue(sSharedSources, stream);
1529
1530 _CFStreamSetSource(stream, NULL, count == 0);
1531
1532 __CFBitClear(stream->flags, SHARED_SOURCE);
1533
1534 __CFSpinUnlock(&sSourceLock);
1535 }
1536
1537 _CFStreamLock(stream);
1538 _CFStreamRemoveRunLoopAndModeFromArray(stream->client->runLoopsAndModes, runLoop, runLoopMode);
1539 checkRLMArray(stream->client->runLoopsAndModes);
1540 _CFStreamUnlock(stream);
1541
1542 if (cb->unschedule) {
1543 cb->unschedule(stream, runLoop, runLoopMode, _CFStreamGetInfoPointer(stream));
1544 }
1545 }
1546
1547 CF_EXPORT void CFReadStreamUnscheduleFromRunLoop(CFReadStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode) {
1548 CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID, void, (NSInputStream *)stream, _unscheduleFromCFRunLoop:runLoop forMode:runLoopMode);
1549 _CFStreamUnscheduleFromRunLoop((struct _CFStream *)stream, runLoop, runLoopMode);
1550 }
1551
1552 void CFWriteStreamUnscheduleFromRunLoop(CFWriteStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode) {
1553 CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID, void, (NSOutputStream *)stream, _unscheduleFromCFRunLoop:runLoop forMode:runLoopMode);
1554 _CFStreamUnscheduleFromRunLoop((struct _CFStream *)stream, runLoop, runLoopMode);
1555 }
1556
1557 static void waitForOpen(struct _CFStream *stream) {
1558 CFRunLoopRef runLoop = CFRunLoopGetCurrent();
1559 CFStringRef privateMode = CFSTR("_kCFStreamBlockingOpenMode");
1560 _CFStreamScheduleWithRunLoop(stream, runLoop, privateMode);
1561 // We cannot call _CFStreamGetStatus, because that tries to set/clear CALLING_CLIENT, which should be set around this entire call (we're within a call from the client). This should be o.k., because we're running the run loop, so our status code should be being updated in a timely fashion....
1562 while (__CFStreamGetStatus(stream) == kCFStreamStatusOpening) {
1563 CFRunLoopRunInMode(privateMode, 1e+20, TRUE);
1564 }
1565 _CFStreamUnscheduleFromRunLoop(stream, runLoop, privateMode);
1566 }
1567
1568 CF_EXPORT CFArrayRef _CFReadStreamGetRunLoopsAndModes(CFReadStreamRef readStream) {
1569 return _CFStreamGetRunLoopsAndModes((struct _CFStream *)readStream);
1570 }
1571
1572 CF_EXPORT CFArrayRef _CFWriteStreamGetRunLoopsAndModes(CFWriteStreamRef writeStream) {
1573 return _CFStreamGetRunLoopsAndModes((struct _CFStream *)writeStream);
1574 }
1575
1576 CF_EXPORT CFArrayRef _CFReadStreamCopyRunLoopsAndModes(CFReadStreamRef readStream) {
1577 return _CFStreamCopyRunLoopsAndModes((struct _CFStream *)readStream);
1578 }
1579
1580 CF_EXPORT CFArrayRef _CFWriteStreamCopyRunLoopsAndModes(CFWriteStreamRef writeStream) {
1581 return _CFStreamCopyRunLoopsAndModes((struct _CFStream *)writeStream);
1582 }
1583
1584 CF_EXPORT void CFReadStreamSignalEvent(CFReadStreamRef stream, CFStreamEventType event, const void *error) {
1585 _CFStreamSignalEvent((struct _CFStream *)stream, event, (CFErrorRef)error, TRUE);
1586 }
1587
1588 CF_EXPORT void CFWriteStreamSignalEvent(CFWriteStreamRef stream, CFStreamEventType event, const void *error) {
1589 _CFStreamSignalEvent((struct _CFStream *)stream, event, (CFErrorRef)error, TRUE);
1590 }
1591
1592 CF_EXPORT void _CFReadStreamSignalEventDelayed(CFReadStreamRef stream, CFStreamEventType event, const void *error) {
1593 _CFStreamSignalEvent((struct _CFStream *)stream, event, (CFErrorRef)error, FALSE);
1594 }
1595
1596 CF_EXPORT void _CFReadStreamClearEvent(CFReadStreamRef readStream, CFStreamEventType event) {
1597 struct _CFStream *stream = (struct _CFStream *)readStream;
1598 if (stream->client) {
1599 stream->client->whatToSignal &= ~event;
1600 }
1601 }
1602
1603 CF_EXPORT void _CFWriteStreamSignalEventDelayed(CFWriteStreamRef stream, CFStreamEventType event, const void *error) {
1604 _CFStreamSignalEvent((struct _CFStream *)stream, event, (CFErrorRef)error, FALSE);
1605 }
1606
1607 CF_EXPORT void *CFReadStreamGetInfoPointer(CFReadStreamRef stream) {
1608 return _CFStreamGetInfoPointer((struct _CFStream *)stream);
1609 }
1610
1611 CF_EXPORT void *CFWriteStreamGetInfoPointer(CFWriteStreamRef stream) {
1612 return _CFStreamGetInfoPointer((struct _CFStream *)stream);
1613 }
1614
1615 /* CF_EXPORT */
1616 void _CFStreamSourceScheduleWithRunLoop(CFRunLoopSourceRef source, CFMutableArrayRef runLoopsAndModes, CFRunLoopRef runLoop, CFStringRef runLoopMode)
1617 {
1618 CFIndex count;
1619 CFRange range;
1620
1621 checkRLMArray(runLoopsAndModes);
1622
1623 count = CFArrayGetCount(runLoopsAndModes);
1624 range = CFRangeMake(0, count);
1625
1626 while (range.length) {
1627
1628 CFIndex i = CFArrayGetFirstIndexOfValue(runLoopsAndModes, range, runLoop);
1629
1630 if (i == kCFNotFound)
1631 break;
1632
1633 if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes, i + 1), runLoopMode))
1634 return;
1635
1636 range.location = i + 2;
1637 range.length = count - range.location;
1638 }
1639
1640 // Add the new values.
1641 CFArrayAppendValue(runLoopsAndModes, runLoop);
1642 CFArrayAppendValue(runLoopsAndModes, runLoopMode);
1643
1644 // Schedule the source on the new loop and mode.
1645 if (source)
1646 CFRunLoopAddSource(runLoop, source, runLoopMode);
1647 }
1648
1649
1650 /* CF_EXPORT */
1651 void _CFStreamSourceUnscheduleFromRunLoop(CFRunLoopSourceRef source, CFMutableArrayRef runLoopsAndModes, CFRunLoopRef runLoop, CFStringRef runLoopMode)
1652 {
1653 CFIndex count;
1654 CFRange range;
1655
1656 count = CFArrayGetCount(runLoopsAndModes);
1657 range = CFRangeMake(0, count);
1658
1659 checkRLMArray(runLoopsAndModes);
1660
1661 while (range.length) {
1662
1663 CFIndex i = CFArrayGetFirstIndexOfValue(runLoopsAndModes, range, runLoop);
1664
1665 // If not found, it's not scheduled on it.
1666 if (i == kCFNotFound)
1667 return;
1668
1669 // Make sure it is scheduled in this mode.
1670 if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes, i + 1), runLoopMode)) {
1671
1672 // Remove mode and runloop from the list.
1673 CFArrayReplaceValues(runLoopsAndModes, CFRangeMake(i, 2), NULL, 0);
1674
1675 // Remove it from the runloop.
1676 if (source)
1677 CFRunLoopRemoveSource(runLoop, source, runLoopMode);
1678
1679 return;
1680 }
1681
1682 range.location = i + 2;
1683 range.length = count - range.location;
1684 }
1685 }
1686
1687
1688 /* CF_EXPORT */
1689 void _CFStreamSourceScheduleWithAllRunLoops(CFRunLoopSourceRef source, CFArrayRef runLoopsAndModes)
1690 {
1691 CFIndex i, count = CFArrayGetCount(runLoopsAndModes);
1692
1693 if (!source)
1694 return;
1695
1696 checkRLMArray(runLoopsAndModes);
1697
1698 for (i = 0; i < count; i += 2) {
1699
1700 // Make sure it's scheduled on all the right loops and modes.
1701 // Go through the array adding the source to all loops and modes.
1702 CFRunLoopAddSource((CFRunLoopRef)CFArrayGetValueAtIndex(runLoopsAndModes, i),
1703 source,
1704 (CFStringRef)CFArrayGetValueAtIndex(runLoopsAndModes, i + 1));
1705 }
1706 }
1707
1708
1709 /* CF_EXPORT */
1710 void _CFStreamSourceUncheduleFromAllRunLoops(CFRunLoopSourceRef source, CFArrayRef runLoopsAndModes)
1711 {
1712 CFIndex i, count = CFArrayGetCount(runLoopsAndModes);
1713
1714 if (!source)
1715 return;
1716
1717 checkRLMArray(runLoopsAndModes);
1718
1719 for (i = 0; i < count; i += 2) {
1720
1721 // Go through the array removing the source from all loops and modes.
1722 CFRunLoopRemoveSource((CFRunLoopRef)CFArrayGetValueAtIndex(runLoopsAndModes, i),
1723 source,
1724 (CFStringRef)CFArrayGetValueAtIndex(runLoopsAndModes, i + 1));
1725 }
1726 }
1727
1728 Boolean _CFStreamRemoveRunLoopAndModeFromArray(CFMutableArrayRef runLoopsAndModes, CFRunLoopRef rl, CFStringRef mode) {
1729 CFIndex idx, cnt;
1730 Boolean found = FALSE;
1731
1732 if (!runLoopsAndModes) return FALSE;
1733
1734 checkRLMArray(runLoopsAndModes);
1735
1736 cnt = CFArrayGetCount(runLoopsAndModes);
1737 for (idx = 0; idx + 1 < cnt; idx += 2) {
1738 if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes, idx), rl) && CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes, idx + 1), mode)) {
1739 CFArrayRemoveValueAtIndex(runLoopsAndModes, idx);
1740 CFArrayRemoveValueAtIndex(runLoopsAndModes, idx);
1741 found = TRUE;
1742 break;
1743 }
1744 }
1745 return found;
1746 }
1747
1748 // Used by NSStream to properly allocate the bridged objects
1749 CF_EXPORT CFIndex _CFStreamInstanceSize(void) {
1750 return sizeof(struct _CFStream);
1751 }
1752
1753 #if DEPLOYMENT_TARGET_WINDOWS
1754 void __CFStreamCleanup(void) {
1755 __CFSpinLock(&sSourceLock);
1756 if (sSharedSources) {
1757 CFIndex count = CFDictionaryGetCount(sSharedSources);
1758 if (count == 0) {
1759 // Only release if empty. If it's still holding streams (which would be a client
1760 // bug leak), freeing this dict would free the streams, which then need to access the
1761 // dict to remove themselves, which leads to a deadlock.
1762 CFRelease(sSharedSources);
1763 sSharedSources = NULL;
1764 } else {
1765 const void ** keys = (const void **)malloc(sizeof(const void *) * count);
1766 #if defined(DEBUG)
1767 int i;
1768 #endif
1769 CFDictionaryGetKeysAndValues(sSharedSources, keys, NULL);
1770 fprintf(stderr, "*** CFNetwork is shutting down, but %ld streams are still scheduled.\n", count);
1771 #if defined(DEBUG)
1772 for (i = 0; i < count;i ++) {
1773 if ((CFGetTypeID(keys[i]) == __kCFReadStreamTypeID) || (CFGetTypeID(keys[i]) == __kCFWriteStreamTypeID)) {
1774 CFShow(keys[i]);
1775 }
1776 }
1777 #endif
1778 }
1779 }
1780 __CFSpinUnlock(&sSourceLock);
1781 }
1782 #endif
1783