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