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