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