]> git.saurik.com Git - apple/cf.git/blob - CFStream.c
CF-550.tar.gz
[apple/cf.git] / CFStream.c
1 /*
2 * Copyright (c) 2009 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 (c) 2000-2009, 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 __private_extern__ CFStreamStatus _CFStreamGetStatus(struct _CFStream *stream);
72 static Boolean _CFStreamRemoveRunLoopAndModeFromArray(CFMutableArrayRef runLoopsAndModes, CFRunLoopRef rl, CFStringRef mode);
73 static void _wakeUpRunLoop(struct _CFStream *stream);
74
75 CF_INLINE const struct _CFStreamCallBacks *_CFStreamGetCallBackPtr(struct _CFStream *stream) {
76 return stream->callBacks;
77 }
78
79 CF_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
88 CF_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
96 CF_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));
101 }
102
103 static 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 {
115 contextDescription = CFStringCreateWithFormat(CFGetAllocator(stream), NULL, CFSTR("info = %p"), _CFStreamGetInfoPointer(stream));
116 }
117 if (CFGetTypeID(cf) == __kCFReadStreamTypeID) {
118 desc = CFStringCreateWithFormat(CFGetAllocator(stream), NULL, CFSTR("<CFReadStream %p>{%@}"), stream, contextDescription);
119 } else {
120 desc = CFStringCreateWithFormat(CFGetAllocator(stream), NULL, CFSTR("<CFWriteStream %p>{%@}"), stream, contextDescription);
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))) {
130 // Stream is not open from the client's perspective; do not callout and do not update our status to "closed"
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
147 CFArrayRef runLoopAndSourceKey;
148 CFMutableArrayRef list;
149 CFIndex c, i;
150
151 __CFSpinLock(&sSourceLock);
152
153 runLoopAndSourceKey = (CFArrayRef)CFDictionaryGetValue(sSharedSources, stream);
154 list = (CFMutableArrayRef)CFDictionaryGetValue(sSharedSources, runLoopAndSourceKey);
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
163 CFAssert(CFArrayGetFirstIndexOfValue(list, CFRangeMake(0, CFArrayGetCount(list)), stream) == kCFNotFound, __kCFLogAssertion, "CFStreamClose: stream found twice in its shared source's list");
164
165 if (!c) {
166 CFRunLoopRemoveSource((CFRunLoopRef)CFArrayGetValueAtIndex(runLoopAndSourceKey, 0), stream->client->rlSource, (CFStringRef)CFArrayGetValueAtIndex(runLoopAndSourceKey, 1));
167 CFRunLoopSourceInvalidate(stream->client->rlSource);
168 CFDictionaryRemoveValue(sSharedSources, runLoopAndSourceKey);
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
186 static void __CFStreamDeallocate(CFTypeRef cf) {
187 struct _CFStream *stream = (struct _CFStream *)cf;
188 const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
189 CFAllocatorRef alloc = CFGetAllocator(stream);
190 // numStreamInstances --;
191
192 // Close the stream
193 _CFStreamClose(stream);
194
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
209 CFArrayRef runLoopAndSourceKey;
210 CFMutableArrayRef list;
211 CFIndex c, i;
212
213 __CFSpinLock(&sSourceLock);
214
215 runLoopAndSourceKey = (CFArrayRef)CFDictionaryGetValue(sSharedSources, stream);
216 list = (CFMutableArrayRef)CFDictionaryGetValue(sSharedSources, runLoopAndSourceKey);
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) {
226 CFRunLoopRemoveSource((CFRunLoopRef)CFArrayGetValueAtIndex(runLoopAndSourceKey, 0), stream->client->rlSource, (CFStringRef)CFArrayGetValueAtIndex(runLoopAndSourceKey, 1));
227 CFRunLoopSourceInvalidate(stream->client->rlSource);
228 CFDictionaryRemoveValue(sSharedSources, runLoopAndSourceKey);
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 }
254 if (stream->error) {
255 if (cb->version < 2) {
256 CFAllocatorDeallocate(alloc, stream->error);
257 } else {
258 CFRelease(stream->error);
259 }
260 }
261 if (!__CFBitIsSet(stream->flags, CONSTANT_CALLBACKS)) {
262 CFAllocatorDeallocate(alloc, (void *)stream->callBacks);
263 }
264 }
265
266 static 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
278 static 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
290 CONST_STRING_DECL(kCFStreamPropertySocketNativeHandle, "kCFStreamPropertySocketNativeHandle")
291 CONST_STRING_DECL(kCFStreamPropertySocketRemoteHostName, "kCFStreamPropertySocketRemoteHostName")
292 CONST_STRING_DECL(kCFStreamPropertySocketRemotePortNumber, "kCFStreamPropertySocketRemotePortNumber")
293 CONST_STRING_DECL(kCFStreamPropertyDataWritten, "kCFStreamPropertyDataWritten")
294 CONST_STRING_DECL(kCFStreamPropertyAppendToFile, "kCFStreamPropertyAppendToFile")
295
296 __private_extern__ void __CFStreamInitialize(void) {
297 __kCFReadStreamTypeID = _CFRuntimeRegisterClass(&__CFReadStreamClass);
298 __kCFWriteStreamTypeID = _CFRuntimeRegisterClass(&__CFWriteStreamClass);
299 }
300
301
302 CF_EXPORT CFTypeID CFReadStreamGetTypeID(void) {
303 return __kCFReadStreamTypeID;
304 }
305
306 CF_EXPORT CFTypeID CFWriteStreamGetTypeID(void) {
307 return __kCFWriteStreamTypeID;
308 }
309
310 static 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);
316 newStream->error = NULL;
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
340 CF_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
355 CF_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;
359 cb = (struct _CFStreamCallBacks *)CFAllocatorAllocate(alloc, sizeof(struct _CFStreamCallBacks), 0);
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;
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;
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;
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;
405 } else {
406 newStream->info = callbacks->create ? callbacks->create((CFReadStreamRef)newStream, info) : info;
407 cb->version = 2;
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;
411 cb->open = (Boolean(*)(struct _CFStream *, CFErrorRef *, Boolean *, void *))callbacks->open;
412 cb->openCompleted = (Boolean (*)(struct _CFStream *, CFErrorRef *, void *))callbacks->openCompleted;
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;
424 }
425
426 newStream->callBacks = cb;
427 return (CFReadStreamRef)newStream;
428 }
429
430 CF_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;
434 cb = (struct _CFStreamCallBacks *)CFAllocatorAllocate(alloc, sizeof(struct _CFStreamCallBacks), 0);
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;
447 cb->open = (Boolean(*)(struct _CFStream *, CFErrorRef *, Boolean *, void *))cbV0->open;
448 cb->openCompleted = (Boolean (*)(struct _CFStream *, CFErrorRef *, void *))cbV0->openCompleted;
449 cb->read = NULL;
450 cb->getBuffer = NULL;
451 cb->canRead = NULL;
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;
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;
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;
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;
486 cb->open = (Boolean(*)(struct _CFStream *, CFErrorRef *, Boolean *, void *))callbacks->open;
487 cb->openCompleted = (Boolean (*)(struct _CFStream *, CFErrorRef *, void *))callbacks->openCompleted;
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
504 static void _signalEventSync(struct _CFStream* stream, CFOptionFlags whatToSignal)
505 {
506 CFOptionFlags eventMask;
507
508 __CFBitSet(stream->flags, CALLING_CLIENT);
509
510 void* info = NULL;
511 void (*release) (void*) = NULL;
512
513 if (stream->client->cbContext.retain == NULL)
514 info = stream->client->cbContext.info;
515 else {
516 info = stream->client->cbContext.retain(stream->client->cbContext.info);
517 release = stream->client->cbContext.release;
518 }
519
520 for (eventMask = 1; eventMask <= whatToSignal; eventMask = eventMask << 1) {
521 if ((eventMask & whatToSignal) && (stream->client->when & eventMask)) {
522 stream->client->cb(stream, eventMask, info);
523
524 /* What happens if the callback sets the client to NULL? We're in a loop here... Hmm. */
525 /* After writing that comment, I see: <rdar://problem/6793636> CFReadStreamSetClient(..., NULL) unsafely releases info pointer immediately */
526 }
527 }
528
529 if (release)
530 (*release) (info);
531
532 __CFBitClear(stream->flags, CALLING_CLIENT);
533 }
534
535 static void _cfstream_solo_signalEventSync(void* info)
536 {
537 CFTypeID typeID = CFGetTypeID((CFTypeRef) info);
538
539 if (typeID != CFReadStreamGetTypeID() && typeID != CFWriteStreamGetTypeID()) {
540 CFLog(__kCFLogAssertion, CFSTR("Expected an read or write stream for %p"), info);
541 #if defined(DEBUG)
542 abort();
543 #endif
544 } else {
545 struct _CFStream* stream = (struct _CFStream*) info;
546 CFOptionFlags whatToSignal = stream->client->whatToSignal;
547 stream->client->whatToSignal = 0;
548
549 /* Since the array version holds a retain, we do it here as well, as opposed to taking a second retain in the client callback */
550 CFRetain(stream);
551 _signalEventSync(stream, whatToSignal);
552 CFRelease(stream);
553 }
554 }
555
556 static void _cfstream_shared_signalEventSync(void* info)
557 {
558 CFTypeID typeID = CFGetTypeID((CFTypeRef) info);
559
560 if (typeID != CFArrayGetTypeID()) {
561 CFLog(__kCFLogAssertion, CFSTR("Expected an array for %p"), info);
562 #if defined(DEBUG)
563 abort();
564 #endif
565 } else {
566 CFMutableArrayRef list = (CFMutableArrayRef) info;
567 CFIndex c, i;
568 CFOptionFlags whatToSignal = 0;
569 struct _CFStream* stream = NULL;
570
571 __CFSpinLock(&sSourceLock);
572
573 /* Looks like, we grab the first stream that wants an event... */
574 /* Note that I grab an extra retain when I pull out the stream here... */
575 c = CFArrayGetCount(list);
576 for (i = 0; i < c; i++) {
577 struct _CFStream* s = (struct _CFStream*)CFArrayGetValueAtIndex(list, i);
578
579 if (s->client->whatToSignal) {
580 stream = s;
581 CFRetain(stream);
582 whatToSignal = stream->client->whatToSignal;
583 s->client->whatToSignal = 0;
584 break;
585 }
586 }
587
588 /* And then we also signal any other streams in this array so that we get them next go? */
589 for (; i < c; i++) {
590 struct _CFStream* s = (struct _CFStream*)CFArrayGetValueAtIndex(list, i);
591 if (s->client->whatToSignal) {
592 CFRunLoopSourceSignal(s->client->rlSource);
593 break;
594 }
595 }
596
597 __CFSpinUnlock(&sSourceLock);
598
599 /* We're sitting here now, possibly with a stream that needs to be processed by the common routine */
600 if (stream) {
601 _signalEventSync(stream, whatToSignal);
602
603 /* Lose our extra retain */
604 CFRelease(stream);
605 }
606 }
607 }
608
609 // 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
610 // are likely to signal the same run loop over and over again. Don't know if we should worry about that.
611 static void _wakeUpRunLoop(struct _CFStream *stream) {
612 CFRunLoopRef rl = NULL;
613 SInt32 idx, cnt;
614 CFArrayRef rlArray;
615 if (!stream->client || !stream->client->runLoopsAndModes) return;
616 rlArray = stream->client->runLoopsAndModes;
617 cnt = CFArrayGetCount(rlArray);
618 if (cnt == 0) return;
619 if (cnt == 2) {
620 rl = (CFRunLoopRef)CFArrayGetValueAtIndex(rlArray, 0);
621 } else {
622 rl = (CFRunLoopRef)CFArrayGetValueAtIndex(rlArray, 0);
623 for (idx = 2; NULL != rl && idx < cnt; idx+=2) {
624 CFRunLoopRef value = (CFRunLoopRef)CFArrayGetValueAtIndex(rlArray, idx);
625 if (value != rl) rl = NULL;
626 }
627 if (NULL == rl) { /* more than one different rl, so we must pick one */
628 for (idx = 0; idx < cnt; idx+=2) {
629 CFRunLoopRef value = (CFRunLoopRef)CFArrayGetValueAtIndex(rlArray, idx);
630 CFStringRef currentMode = CFRunLoopCopyCurrentMode(value);
631 if (NULL != currentMode && CFEqual(currentMode, CFArrayGetValueAtIndex(rlArray, idx+1)) && CFRunLoopIsWaiting(value)) {
632 CFRelease(currentMode);
633 rl = value;
634 break;
635 }
636 if (NULL != currentMode) CFRelease(currentMode);
637 }
638 if (NULL == rl) { /* didn't choose one above, so choose first */
639 rl = (CFRunLoopRef)CFArrayGetValueAtIndex(rlArray, 0);
640 }
641 }
642 }
643 if (NULL != rl && CFRunLoopIsWaiting(rl)) CFRunLoopWakeUp(rl);
644 }
645
646 __private_extern__ void _CFStreamSignalEvent(struct _CFStream *stream, CFStreamEventType event, CFErrorRef error, Boolean synchronousAllowed) {
647 // Update our internal status; we must use the primitive __CFStreamGetStatus(), because CFStreamGetStatus() calls us, and we can end up in an infinite loop.
648 CFStreamStatus status = __CFStreamGetStatus(stream);
649
650 // Sanity check the event
651 if (status == kCFStreamStatusNotOpen) {
652 // No events allowed; this is almost certainly a bug in the stream's implementation
653 CFLog(__kCFLogAssertion, CFSTR("Stream %p is sending an event before being opened"), stream);
654 event = 0;
655 } else if (status == kCFStreamStatusClosed || status == kCFStreamStatusError) {
656 // no further events are allowed
657 event = 0;
658 } else if (status == kCFStreamStatusAtEnd) {
659 // Only error events are allowed
660 event &= kCFStreamEventErrorOccurred;
661 } else if (status != kCFStreamStatusOpening) {
662 // cannot send open completed; that happened already
663 event &= ~kCFStreamEventOpenCompleted;
664 }
665
666 // Change status if appropriate
667 if (event & kCFStreamEventOpenCompleted && status == kCFStreamStatusOpening) {
668 _CFStreamSetStatusCode(stream, kCFStreamStatusOpen);
669 }
670 if (event & kCFStreamEventEndEncountered && status < kCFStreamStatusAtEnd) {
671 _CFStreamSetStatusCode(stream, kCFStreamStatusAtEnd);
672 }
673 if (event & kCFStreamEventErrorOccurred) {
674 if (_CFStreamGetCallBackPtr(stream)->version < 2) {
675 _CFStreamSetStreamError(stream, (CFStreamError *)error);
676 } else {
677 CFAssert(error, __kCFLogAssertion, "CFStream: kCFStreamEventErrorOccurred signalled, but error is NULL!");
678 CFRetain(error);
679 if (stream->error) CFRelease(stream->error);
680 stream->error = error;
681 }
682 _CFStreamSetStatusCode(stream, kCFStreamStatusError);
683 }
684
685 // Now signal any pertinent event
686 if (stream->client && stream->client->rlSource && (stream->client->when & event)) {
687
688 Boolean signalNow = FALSE;
689
690 stream->client->whatToSignal |= event;
691
692 if (synchronousAllowed && !__CFBitIsSet(stream->flags, CALLING_CLIENT)) {
693
694 CFRunLoopRef rl = CFRunLoopGetCurrent();
695 CFStringRef mode = CFRunLoopCopyCurrentMode(rl);
696
697 if (mode) {
698 if (CFRunLoopContainsSource(rl, stream->client->rlSource, mode))
699 signalNow = TRUE;
700 CFRelease(mode);
701 }
702 }
703
704 if (signalNow) {
705 // Can call out safely right now
706 _cfstream_solo_signalEventSync(stream);
707 } else {
708 // Schedule for later delivery
709 CFRunLoopSourceSignal(stream->client->rlSource);
710 _wakeUpRunLoop(stream);
711 }
712 }
713 }
714
715 __private_extern__ CFStreamStatus _CFStreamGetStatus(struct _CFStream *stream) {
716 CFStreamStatus status = __CFStreamGetStatus(stream);
717 // 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.
718 __CFBitSet(stream->flags, CALLING_CLIENT);
719 if (status == kCFStreamStatusOpening) {
720 const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
721 if (cb->openCompleted) {
722 Boolean isComplete;
723 if (cb->version < 2) {
724 CFStreamError err = {0, 0};
725 isComplete = ((_CFStreamCBOpenCompletedV1)(cb->openCompleted))(stream, &err, _CFStreamGetInfoPointer(stream));
726 if (err.error != 0) _CFStreamSetStreamError(stream, &err);
727 } else {
728 isComplete = cb->openCompleted(stream, &(stream->error), _CFStreamGetInfoPointer(stream));
729 }
730 if (isComplete) {
731 if (!stream->error) {
732 status = kCFStreamStatusOpen;
733 } else {
734 status = kCFStreamStatusError;
735 }
736 _CFStreamSetStatusCode(stream, status);
737 if (status == kCFStreamStatusOpen) {
738 _CFStreamScheduleEvent(stream, kCFStreamEventOpenCompleted);
739 } else {
740 _CFStreamScheduleEvent(stream, kCFStreamEventErrorOccurred);
741 }
742 }
743 }
744 }
745 __CFBitClear(stream->flags, CALLING_CLIENT);
746 return status;
747 }
748
749 CF_EXPORT CFStreamStatus CFReadStreamGetStatus(CFReadStreamRef stream) {
750 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID, CFStreamStatus, stream, "streamStatus");
751 return _CFStreamGetStatus((struct _CFStream *)stream);
752 }
753
754 CF_EXPORT CFStreamStatus CFWriteStreamGetStatus(CFWriteStreamRef stream) {
755 CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID, CFStreamStatus, stream, "streamStatus");
756 return _CFStreamGetStatus((struct _CFStream *)stream);
757 }
758
759 static CFStreamError _CFStreamGetStreamError(struct _CFStream *stream) {
760 CFStreamError result;
761 if (!stream->error) {
762 result.error = 0;
763 result.domain = 0;
764 } else if (_CFStreamGetCallBackPtr(stream)->version < 2) {
765 CFStreamError *streamError = (CFStreamError *)(stream->error);
766 result.error = streamError->error;
767 result.domain = streamError->domain;
768 } else {
769 result = _CFStreamErrorFromError(stream->error);
770 }
771 return result;
772 }
773
774 CF_EXPORT CFStreamError CFReadStreamGetError(CFReadStreamRef stream) {
775 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID, CFStreamError, stream, "_cfStreamError");
776 return _CFStreamGetStreamError((struct _CFStream *)stream);
777 }
778
779 CF_EXPORT CFStreamError CFWriteStreamGetError(CFWriteStreamRef stream) {
780 CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID, CFStreamError, stream, "_cfStreamError");
781 return _CFStreamGetStreamError((struct _CFStream *)stream);
782 }
783
784 static CFErrorRef _CFStreamCopyError(struct _CFStream *stream) {
785 if (!stream->error) {
786 return NULL;
787 } else if (_CFStreamGetCallBackPtr(stream)->version < 2) {
788 return _CFErrorFromStreamError(CFGetAllocator(stream), (CFStreamError *)(stream->error));
789 } else {
790 CFRetain(stream->error);
791 return stream->error;
792 }
793 }
794
795 CF_EXPORT CFErrorRef CFReadStreamCopyError(CFReadStreamRef stream) {
796 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID, CFErrorRef, stream, "streamError");
797 return _CFStreamCopyError((struct _CFStream *)stream);
798 }
799
800 CF_EXPORT CFErrorRef CFWriteStreamCopyError(CFWriteStreamRef stream) {
801 return _CFStreamCopyError((struct _CFStream *)stream);
802 CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID, CFErrorRef, stream, "streamError");
803 }
804
805 __private_extern__ Boolean _CFStreamOpen(struct _CFStream *stream) {
806 const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
807 Boolean success, openComplete;
808 if (_CFStreamGetStatus(stream) != kCFStreamStatusNotOpen) {
809 return FALSE;
810 }
811 __CFBitSet(stream->flags, CALLING_CLIENT);
812 _CFStreamSetStatusCode(stream, kCFStreamStatusOpening);
813 if (cb->open) {
814 if (cb->version < 2) {
815 CFStreamError err = {0, 0};
816 success = ((_CFStreamCBOpenV1)(cb->open))(stream, &err, &openComplete, _CFStreamGetInfoPointer(stream));
817 if (err.error != 0) _CFStreamSetStreamError(stream, &err);
818 } else {
819 success = cb->open(stream, &(stream->error), &openComplete, _CFStreamGetInfoPointer(stream));
820 }
821 } else {
822 success = TRUE;
823 openComplete = TRUE;
824 }
825 if (openComplete) {
826 if (success) {
827 // 2957690 - Guard against the possibility that the stream has already signalled itself in to a later state (like AtEnd)
828 if (__CFStreamGetStatus(stream) == kCFStreamStatusOpening) {
829 _CFStreamSetStatusCode(stream, kCFStreamStatusOpen);
830 }
831 _CFStreamScheduleEvent(stream, kCFStreamEventOpenCompleted);
832 } else {
833 #if DEPLOYMENT_TARGET_WINDOWS
834 _CFStreamClose(stream);
835 #endif
836 _CFStreamSetStatusCode(stream, kCFStreamStatusError);
837 _CFStreamScheduleEvent(stream, kCFStreamEventErrorOccurred);
838 }
839 }
840 __CFBitClear(stream->flags, CALLING_CLIENT);
841 return success;
842 }
843
844 CF_EXPORT Boolean CFReadStreamOpen(CFReadStreamRef stream) {
845 if(CF_IS_OBJC(__kCFReadStreamTypeID, stream)) {
846 CF_OBJC_VOIDCALL0(stream, "open");
847 return TRUE;
848 }
849 return _CFStreamOpen((struct _CFStream *)stream);
850 }
851
852 CF_EXPORT Boolean CFWriteStreamOpen(CFWriteStreamRef stream) {
853 if(CF_IS_OBJC(__kCFWriteStreamTypeID, stream)) {
854 CF_OBJC_VOIDCALL0(stream, "open");
855 return TRUE;
856 }
857 return _CFStreamOpen((struct _CFStream *)stream);
858 }
859
860 CF_EXPORT void CFReadStreamClose(CFReadStreamRef stream) {
861 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID, void, stream, "close");
862 _CFStreamClose((struct _CFStream *)stream);
863 }
864
865 CF_EXPORT void CFWriteStreamClose(CFWriteStreamRef stream) {
866 CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID, void, stream, "close");
867 _CFStreamClose((struct _CFStream *)stream);
868 }
869
870 CF_EXPORT Boolean CFReadStreamHasBytesAvailable(CFReadStreamRef readStream) {
871 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID, Boolean, readStream, "hasBytesAvailable");
872 struct _CFStream *stream = (struct _CFStream *)readStream;
873 CFStreamStatus status = _CFStreamGetStatus(stream);
874 const struct _CFStreamCallBacks *cb;
875 if (status != kCFStreamStatusOpen && status != kCFStreamStatusReading) {
876 return FALSE;
877 }
878 cb = _CFStreamGetCallBackPtr(stream);
879 if (cb->canRead == NULL) {
880 return TRUE; // No way to know without trying....
881 } else {
882 Boolean result;
883 __CFBitSet(stream->flags, CALLING_CLIENT);
884 if (cb->version < 2) {
885 result = ((_CFStreamCBCanReadV1)(cb->canRead))((CFReadStreamRef)stream, _CFStreamGetInfoPointer(stream));
886 } else {
887 result = cb->canRead((CFReadStreamRef)stream, &(stream->error), _CFStreamGetInfoPointer(stream));
888 if (stream->error) {
889 _CFStreamSetStatusCode(stream, kCFStreamStatusError);
890 _CFStreamScheduleEvent(stream, kCFStreamEventErrorOccurred);
891 }
892 }
893 __CFBitClear(stream->flags, CALLING_CLIENT);
894 return result;
895 }
896 }
897
898 static void waitForOpen(struct _CFStream *stream);
899 CFIndex CFReadStreamRead(CFReadStreamRef readStream, UInt8 *buffer, CFIndex bufferLength) {
900 CF_OBJC_FUNCDISPATCH2(__kCFReadStreamTypeID, CFIndex, readStream, "read:maxLength:", buffer, bufferLength);
901 struct _CFStream *stream = (struct _CFStream *)readStream;
902 CFStreamStatus status = _CFStreamGetStatus(stream);
903 const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
904 if (status == kCFStreamStatusOpening) {
905 __CFBitSet(stream->flags, CALLING_CLIENT);
906 waitForOpen(stream);
907 __CFBitClear(stream->flags, CALLING_CLIENT);
908 status = _CFStreamGetStatus(stream);
909 }
910
911 if (status != kCFStreamStatusOpen && status != kCFStreamStatusReading && status != kCFStreamStatusAtEnd) {
912 return -1;
913 } else if (status == kCFStreamStatusAtEnd) {
914 return 0;
915 } else {
916 Boolean atEOF;
917 CFIndex bytesRead;
918 __CFBitSet(stream->flags, CALLING_CLIENT);
919 if (stream->client) {
920 stream->client->whatToSignal &= ~kCFStreamEventHasBytesAvailable;
921 }
922 _CFStreamSetStatusCode(stream, kCFStreamStatusReading);
923 if (cb->version < 2) {
924 CFStreamError err = {0, 0};
925 bytesRead = ((_CFStreamCBReadV1)(cb->read))((CFReadStreamRef)stream, buffer, bufferLength, &err, &atEOF, _CFStreamGetInfoPointer(stream));
926 if (err.error != 0) _CFStreamSetStreamError(stream, &err);
927 } else {
928 bytesRead = cb->read((CFReadStreamRef)stream, buffer, bufferLength, &(stream->error), &atEOF, _CFStreamGetInfoPointer(stream));
929 }
930 if (stream->error) {
931 bytesRead = -1;
932 _CFStreamSetStatusCode(stream, kCFStreamStatusError);
933 _CFStreamScheduleEvent(stream, kCFStreamEventErrorOccurred);
934 } else if (atEOF) {
935 _CFStreamSetStatusCode(stream, kCFStreamStatusAtEnd);
936 _CFStreamScheduleEvent(stream, kCFStreamEventEndEncountered);
937 } else {
938 _CFStreamSetStatusCode(stream, kCFStreamStatusOpen);
939 }
940 __CFBitClear(stream->flags, CALLING_CLIENT);
941 return bytesRead;
942 }
943 }
944
945 CF_EXPORT const UInt8 *CFReadStreamGetBuffer(CFReadStreamRef readStream, CFIndex maxBytesToRead, CFIndex *numBytesRead) {
946 if (CF_IS_OBJC(__kCFReadStreamTypeID, readStream)) {
947 uint8_t *bufPtr = NULL;
948 Boolean gotBytes;
949 CF_OBJC_CALL2(Boolean, gotBytes, readStream, "getBuffer:length:", &bufPtr, numBytesRead);
950 if(gotBytes) {
951 return (const UInt8 *)bufPtr;
952 } else {
953 return NULL;
954 }
955 }
956 struct _CFStream *stream = (struct _CFStream *)readStream;
957 CFStreamStatus status = _CFStreamGetStatus(stream);
958 const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
959 const UInt8 *buffer;
960 if (status == kCFStreamStatusOpening) {
961 __CFBitSet(stream->flags, CALLING_CLIENT);
962 waitForOpen(stream);
963 __CFBitClear(stream->flags, CALLING_CLIENT);
964 status = _CFStreamGetStatus(stream);
965 }
966 if (status != kCFStreamStatusOpen && status != kCFStreamStatusReading && status != kCFStreamStatusAtEnd) {
967 *numBytesRead = -1;
968 buffer = NULL;
969 } else if (status == kCFStreamStatusAtEnd || cb->getBuffer == NULL) {
970 *numBytesRead = 0;
971 buffer = NULL;
972 } else {
973 Boolean atEOF;
974 Boolean hadBytes = stream->client && (stream->client->whatToSignal & kCFStreamEventHasBytesAvailable);
975 __CFBitSet(stream->flags, CALLING_CLIENT);
976 if (hadBytes) {
977 stream->client->whatToSignal &= ~kCFStreamEventHasBytesAvailable;
978 }
979 _CFStreamSetStatusCode(stream, kCFStreamStatusReading);
980 if (cb->version < 2) {
981 CFStreamError err = {0, 0};
982 buffer = ((_CFStreamCBGetBufferV1)(cb->getBuffer))((CFReadStreamRef)stream, maxBytesToRead, numBytesRead, &err, &atEOF, _CFStreamGetInfoPointer(stream));
983 if (err.error != 0) _CFStreamSetStreamError(stream, &err);
984 } else {
985 buffer = cb->getBuffer((CFReadStreamRef)stream, maxBytesToRead, numBytesRead, &(stream->error), &atEOF, _CFStreamGetInfoPointer(stream));
986 }
987 if (stream->error) {
988 *numBytesRead = -1;
989 _CFStreamSetStatusCode(stream, kCFStreamStatusError);
990 buffer = NULL;
991 _CFStreamScheduleEvent(stream, kCFStreamEventErrorOccurred);
992 } else if (atEOF) {
993 _CFStreamSetStatusCode(stream, kCFStreamStatusAtEnd);
994 _CFStreamScheduleEvent(stream, kCFStreamEventEndEncountered);
995 } else {
996 if (!buffer && hadBytes) {
997 stream->client->whatToSignal |= kCFStreamEventHasBytesAvailable;
998 }
999 _CFStreamSetStatusCode(stream, kCFStreamStatusOpen);
1000 }
1001 __CFBitClear(stream->flags, CALLING_CLIENT);
1002 }
1003 return buffer;
1004 }
1005
1006 CF_EXPORT Boolean CFWriteStreamCanAcceptBytes(CFWriteStreamRef writeStream) {
1007 CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID, Boolean, writeStream, "hasSpaceAvailable");
1008 struct _CFStream *stream = (struct _CFStream *)writeStream;
1009 CFStreamStatus status = _CFStreamGetStatus(stream);
1010 const struct _CFStreamCallBacks *cb;
1011 if (status != kCFStreamStatusOpen && status != kCFStreamStatusWriting) {
1012 return FALSE;
1013 }
1014 cb = _CFStreamGetCallBackPtr(stream);
1015 if (cb->canWrite == NULL) {
1016 return TRUE; // No way to know without trying....
1017 } else {
1018 Boolean result;
1019 __CFBitSet(stream->flags, CALLING_CLIENT);
1020 if (cb->version < 2) {
1021 result = ((_CFStreamCBCanWriteV1)(cb->canWrite))((CFWriteStreamRef)stream, _CFStreamGetInfoPointer(stream));
1022 } else {
1023 result = cb->canWrite((CFWriteStreamRef)stream, &(stream->error), _CFStreamGetInfoPointer(stream));
1024 if (stream->error) {
1025 _CFStreamSetStatusCode(stream, kCFStreamStatusError);
1026 _CFStreamScheduleEvent(stream, kCFStreamEventErrorOccurred);
1027 }
1028 }
1029 __CFBitClear(stream->flags, CALLING_CLIENT);
1030 return result;
1031 }
1032 }
1033
1034 CF_EXPORT CFIndex CFWriteStreamWrite(CFWriteStreamRef writeStream, const UInt8 *buffer, CFIndex bufferLength) {
1035 CF_OBJC_FUNCDISPATCH2(__kCFWriteStreamTypeID, CFIndex, writeStream, "write:maxLength:", buffer, bufferLength);
1036 struct _CFStream *stream = (struct _CFStream *)writeStream;
1037 CFStreamStatus status = _CFStreamGetStatus(stream);
1038 const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
1039 if (status == kCFStreamStatusOpening) {
1040 __CFBitSet(stream->flags, CALLING_CLIENT);
1041 waitForOpen(stream);
1042 __CFBitClear(stream->flags, CALLING_CLIENT);
1043 status = _CFStreamGetStatus(stream);
1044 }
1045 if (status != kCFStreamStatusOpen && status != kCFStreamStatusWriting) {
1046 return -1;
1047 } else {
1048 CFIndex result;
1049 __CFBitSet(stream->flags, CALLING_CLIENT);
1050 _CFStreamSetStatusCode(stream, kCFStreamStatusWriting);
1051 if (stream->client) {
1052 stream->client->whatToSignal &= ~kCFStreamEventCanAcceptBytes;
1053 }
1054 if (cb->version < 2) {
1055 CFStreamError err = {0, 0};
1056 result = ((_CFStreamCBWriteV1)(cb->write))((CFWriteStreamRef)stream, buffer, bufferLength, &err, _CFStreamGetInfoPointer(stream));
1057 if (err.error) _CFStreamSetStreamError(stream, &err);
1058 } else {
1059 result = cb->write((CFWriteStreamRef)stream, buffer, bufferLength, &(stream->error), _CFStreamGetInfoPointer(stream));
1060 }
1061 if (stream->error) {
1062 _CFStreamSetStatusCode(stream, kCFStreamStatusError);
1063 _CFStreamScheduleEvent(stream, kCFStreamEventErrorOccurred);
1064 } else if (result == 0) {
1065 _CFStreamSetStatusCode(stream, kCFStreamStatusAtEnd);
1066 _CFStreamScheduleEvent(stream, kCFStreamEventEndEncountered);
1067 } else {
1068 _CFStreamSetStatusCode(stream, kCFStreamStatusOpen);
1069 }
1070 __CFBitClear(stream->flags, CALLING_CLIENT);
1071 return result;
1072 }
1073 }
1074
1075 __private_extern__ CFTypeRef _CFStreamCopyProperty(struct _CFStream *stream, CFStringRef propertyName) {
1076 const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
1077 if (cb->copyProperty == NULL) {
1078 return NULL;
1079 } else {
1080 CFTypeRef result;
1081 __CFBitSet(stream->flags, CALLING_CLIENT);
1082 result = cb->copyProperty(stream, propertyName, _CFStreamGetInfoPointer(stream));
1083 __CFBitClear(stream->flags, CALLING_CLIENT);
1084 return result;
1085 }
1086 }
1087
1088 CF_EXPORT CFTypeRef CFReadStreamCopyProperty(CFReadStreamRef stream, CFStringRef propertyName) {
1089 CF_OBJC_FUNCDISPATCH1(__kCFReadStreamTypeID, CFTypeRef, stream, "propertyForKey:", propertyName);
1090 return _CFStreamCopyProperty((struct _CFStream *)stream, propertyName);
1091 }
1092
1093 CF_EXPORT CFTypeRef CFWriteStreamCopyProperty(CFWriteStreamRef stream, CFStringRef propertyName) {
1094 CF_OBJC_FUNCDISPATCH1(__kCFWriteStreamTypeID, CFTypeRef, stream, "propertyForKey:", propertyName);
1095 return _CFStreamCopyProperty((struct _CFStream *)stream, propertyName);
1096 }
1097
1098 __private_extern__ Boolean _CFStreamSetProperty(struct _CFStream *stream, CFStringRef prop, CFTypeRef val) {
1099 const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
1100 if (cb->setProperty == NULL) {
1101 return FALSE;
1102 } else {
1103 Boolean result;
1104 __CFBitSet(stream->flags, CALLING_CLIENT);
1105 result = cb->setProperty(stream, prop, val, _CFStreamGetInfoPointer(stream));
1106 __CFBitClear(stream->flags, CALLING_CLIENT);
1107 return result;
1108 }
1109 }
1110
1111 CF_EXPORT
1112 Boolean CFReadStreamSetProperty(CFReadStreamRef stream, CFStringRef propertyName, CFTypeRef propertyValue) {
1113 CF_OBJC_FUNCDISPATCH2(__kCFReadStreamTypeID, Boolean, stream, "setProperty:forKey:", propertyValue, propertyName);
1114 return _CFStreamSetProperty((struct _CFStream *)stream, propertyName, propertyValue);
1115 }
1116
1117 CF_EXPORT
1118 Boolean CFWriteStreamSetProperty(CFWriteStreamRef stream, CFStringRef propertyName, CFTypeRef propertyValue) {
1119 CF_OBJC_FUNCDISPATCH2(__kCFWriteStreamTypeID, Boolean, stream, "setProperty:forKey:", propertyValue, propertyName);
1120 return _CFStreamSetProperty((struct _CFStream *)stream, propertyName, propertyValue);
1121 }
1122
1123 static void _initializeClient(struct _CFStream *stream) {
1124 const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
1125 if (!cb->schedule) return; // Do we wish to allow this?
1126 stream->client = (struct _CFStreamClient *)CFAllocatorAllocate(CFGetAllocator(stream), sizeof(struct _CFStreamClient), 0);
1127 memset(stream->client, 0, sizeof(struct _CFStreamClient));
1128 }
1129
1130 /* If we add a setClient callback to the concrete stream callbacks, we must set/clear CALLING_CLIENT around it */
1131 __private_extern__ Boolean _CFStreamSetClient(struct _CFStream *stream, CFOptionFlags streamEvents, void (*clientCB)(struct _CFStream *, CFStreamEventType, void *), CFStreamClientContext *clientCallBackContext) {
1132
1133 Boolean removingClient = (streamEvents == kCFStreamEventNone || clientCB == NULL || clientCallBackContext == NULL);
1134 if (removingClient) {
1135 clientCB = NULL;
1136 streamEvents = kCFStreamEventNone;
1137 clientCallBackContext = NULL;
1138 }
1139 if (!stream->client) {
1140 if (removingClient) {
1141 // We have no client now, and we've been asked to add none???
1142 return TRUE;
1143 }
1144 _initializeClient(stream);
1145 if (!stream->client) {
1146 // Asynch not supported
1147 return FALSE;
1148 }
1149 }
1150 if (stream->client->cb && stream->client->cbContext.release) {
1151 stream->client->cbContext.release(stream->client->cbContext.info);
1152 }
1153 stream->client->cb = clientCB;
1154 if (clientCallBackContext) {
1155 stream->client->cbContext.version = clientCallBackContext->version;
1156 stream->client->cbContext.retain = clientCallBackContext->retain;
1157 stream->client->cbContext.release = clientCallBackContext->release;
1158 stream->client->cbContext.copyDescription = clientCallBackContext->copyDescription;
1159 stream->client->cbContext.info = (clientCallBackContext->retain && clientCallBackContext->info) ? clientCallBackContext->retain(clientCallBackContext->info) : clientCallBackContext->info;
1160 } else {
1161 stream->client->cbContext.retain = NULL;
1162 stream->client->cbContext.release = NULL;
1163 stream->client->cbContext.copyDescription = NULL;
1164 stream->client->cbContext.info = NULL;
1165 }
1166 if (stream->client->when != streamEvents) {
1167 const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
1168 stream->client->when = streamEvents;
1169 if (cb->requestEvents) {
1170 cb->requestEvents(stream, streamEvents, _CFStreamGetInfoPointer(stream));
1171 }
1172 }
1173 return TRUE;
1174 }
1175
1176 CF_EXPORT Boolean CFReadStreamSetClient(CFReadStreamRef readStream, CFOptionFlags streamEvents, CFReadStreamClientCallBack clientCB, CFStreamClientContext *clientContext) {
1177 CF_OBJC_FUNCDISPATCH3(__kCFReadStreamTypeID, Boolean, readStream, "_setCFClientFlags:callback:context:", streamEvents, clientCB, clientContext);
1178 streamEvents &= ~kCFStreamEventCanAcceptBytes;
1179 return _CFStreamSetClient((struct _CFStream *)readStream, streamEvents, (void (*)(struct _CFStream *, CFStreamEventType, void *))clientCB, clientContext);
1180 }
1181
1182 CF_EXPORT Boolean CFWriteStreamSetClient(CFWriteStreamRef writeStream, CFOptionFlags streamEvents, CFWriteStreamClientCallBack clientCB, CFStreamClientContext *clientContext) {
1183 CF_OBJC_FUNCDISPATCH3(__kCFWriteStreamTypeID, Boolean, writeStream, "_setCFClientFlags:callback:context:", streamEvents, clientCB, clientContext);
1184 streamEvents &= ~kCFStreamEventHasBytesAvailable;
1185 return _CFStreamSetClient((struct _CFStream *)writeStream, streamEvents, (void (*)(struct _CFStream *, CFStreamEventType, void *))clientCB, clientContext);
1186 }
1187
1188 CF_INLINE void *_CFStreamGetClient(struct _CFStream *stream) {
1189 if (stream->client) return stream->client->cbContext.info;
1190 else return NULL;
1191 }
1192
1193 CF_EXPORT void *_CFReadStreamGetClient(CFReadStreamRef readStream) {
1194 return _CFStreamGetClient((struct _CFStream *)readStream);
1195 }
1196
1197 CF_EXPORT void *_CFWriteStreamGetClient(CFWriteStreamRef writeStream) {
1198 return _CFStreamGetClient((struct _CFStream *)writeStream);
1199 }
1200
1201
1202 __private_extern__ void _CFStreamScheduleWithRunLoop(struct _CFStream *stream, CFRunLoopRef runLoop, CFStringRef runLoopMode) {
1203 const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
1204
1205 if (!stream->client) {
1206 _initializeClient(stream);
1207 if (!stream->client) return; // we don't support asynch.
1208 }
1209
1210 if (!stream->client->rlSource) {
1211 /* No source, so we join the shared source group */
1212 CFTypeRef a[] = { runLoop, runLoopMode };
1213
1214 CFArrayRef runLoopAndSourceKey = CFArrayCreate(kCFAllocatorSystemDefault, a, sizeof(a) / sizeof(a[0]), &kCFTypeArrayCallBacks);
1215
1216 __CFSpinLock(&sSourceLock);
1217
1218 if (!sSharedSources)
1219 sSharedSources = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1220
1221 CFMutableArrayRef listOfStreamsSharingASource = (CFMutableArrayRef)CFDictionaryGetValue(sSharedSources, runLoopAndSourceKey);
1222 if (listOfStreamsSharingASource) {
1223 stream->client->rlSource = (CFRunLoopSourceRef)CFRetain(((struct _CFStream*)CFArrayGetValueAtIndex(listOfStreamsSharingASource, 0))->client->rlSource);
1224 CFRetain(listOfStreamsSharingASource);
1225 }
1226 else {
1227 CFRunLoopSourceContext ctxt = {
1228 0,
1229 NULL,
1230 CFRetain,
1231 CFRelease,
1232 (CFStringRef(*)(const void *))CFCopyDescription,
1233 NULL,
1234 NULL,
1235 NULL,
1236 NULL,
1237 (void(*)(void *))_cfstream_shared_signalEventSync
1238 };
1239
1240 listOfStreamsSharingASource = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
1241 CFDictionaryAddValue(sSharedSources, runLoopAndSourceKey, listOfStreamsSharingASource);
1242
1243 ctxt.info = listOfStreamsSharingASource;
1244
1245 stream->client->rlSource = CFRunLoopSourceCreate(kCFAllocatorSystemDefault, 0, &ctxt);
1246
1247 CFRunLoopAddSource(runLoop, stream->client->rlSource, runLoopMode);
1248 }
1249
1250 CFArrayAppendValue(listOfStreamsSharingASource, stream);
1251 CFDictionaryAddValue(sSharedSources, stream, runLoopAndSourceKey);
1252
1253 CFRelease(runLoopAndSourceKey);
1254 CFRelease(listOfStreamsSharingASource);
1255
1256 __CFBitSet(stream->flags, SHARED_SOURCE);
1257
1258 __CFSpinUnlock(&sSourceLock);
1259 }
1260 else if (__CFBitIsSet(stream->flags, SHARED_SOURCE)) {
1261 /* We were sharing, but now we'll get our own source */
1262
1263 CFArrayRef runLoopAndSourceKey;
1264 CFMutableArrayRef listOfStreamsSharingASource;
1265 CFIndex c, i;
1266
1267 CFAllocatorRef alloc = CFGetAllocator(stream);
1268 CFRunLoopSourceContext ctxt = {
1269 0,
1270 (void *)stream,
1271 NULL, // Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop
1272 NULL, // Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop
1273 (CFStringRef(*)(const void *))CFCopyDescription,
1274 NULL,
1275 NULL,
1276 NULL,
1277 NULL,
1278 (void(*)(void *))_cfstream_solo_signalEventSync
1279 };
1280
1281 __CFSpinLock(&sSourceLock);
1282
1283 runLoopAndSourceKey = (CFArrayRef)CFRetain((CFTypeRef)CFDictionaryGetValue(sSharedSources, stream));
1284 listOfStreamsSharingASource = (CFMutableArrayRef)CFDictionaryGetValue(sSharedSources, runLoopAndSourceKey);
1285
1286 c = CFArrayGetCount(listOfStreamsSharingASource);
1287 i = CFArrayGetFirstIndexOfValue(listOfStreamsSharingASource, CFRangeMake(0, c), stream);
1288 if (i != kCFNotFound) {
1289 CFArrayRemoveValueAtIndex(listOfStreamsSharingASource, i);
1290 c--;
1291 }
1292
1293 if (!c) {
1294 CFRunLoopRemoveSource((CFRunLoopRef)CFArrayGetValueAtIndex(runLoopAndSourceKey, 0), stream->client->rlSource, (CFStringRef)CFArrayGetValueAtIndex(runLoopAndSourceKey, 1));
1295 CFRunLoopSourceInvalidate(stream->client->rlSource);
1296 CFDictionaryRemoveValue(sSharedSources, runLoopAndSourceKey);
1297 }
1298
1299 CFDictionaryRemoveValue(sSharedSources, stream);
1300
1301 CFRelease(stream->client->rlSource);
1302 __CFBitClear(stream->flags, SHARED_SOURCE);
1303
1304 __CFSpinUnlock(&sSourceLock);
1305
1306 stream->client->rlSource = CFRunLoopSourceCreate(alloc, 0, &ctxt);
1307
1308 CFRunLoopAddSource((CFRunLoopRef)CFArrayGetValueAtIndex(runLoopAndSourceKey, 0), stream->client->rlSource, (CFStringRef)CFArrayGetValueAtIndex(runLoopAndSourceKey, 1));
1309
1310 CFRelease(runLoopAndSourceKey);
1311
1312 CFRunLoopAddSource(runLoop, stream->client->rlSource, runLoopMode);
1313 } else {
1314 /* We're not sharing, so just add the source to the rl & mode */
1315 CFRunLoopAddSource(runLoop, stream->client->rlSource, runLoopMode);
1316 }
1317
1318 if (!stream->client->runLoopsAndModes) {
1319 stream->client->runLoopsAndModes = CFArrayCreateMutable(CFGetAllocator(stream), 0, &kCFTypeArrayCallBacks);
1320 }
1321 CFArrayAppendValue(stream->client->runLoopsAndModes, runLoop);
1322 CFArrayAppendValue(stream->client->runLoopsAndModes, runLoopMode);
1323
1324 if (cb->schedule) {
1325 __CFBitSet(stream->flags, CALLING_CLIENT);
1326 cb->schedule(stream, runLoop, runLoopMode, _CFStreamGetInfoPointer(stream));
1327 __CFBitClear(stream->flags, CALLING_CLIENT);
1328 }
1329
1330 /*
1331 * If we've got events pending, we need to wake up and signal
1332 */
1333 if (stream->client->whatToSignal != 0) {
1334 CFRunLoopSourceSignal(stream->client->rlSource);
1335 _wakeUpRunLoop(stream);
1336 }
1337 }
1338
1339 CF_EXPORT void CFReadStreamScheduleWithRunLoop(CFReadStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode) {
1340 CF_OBJC_FUNCDISPATCH2(__kCFReadStreamTypeID, void, stream, "_scheduleInCFRunLoop:forMode:", runLoop, runLoopMode);
1341 _CFStreamScheduleWithRunLoop((struct _CFStream *)stream, runLoop, runLoopMode);
1342 }
1343
1344 CF_EXPORT void CFWriteStreamScheduleWithRunLoop(CFWriteStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode) {
1345 CF_OBJC_FUNCDISPATCH2(__kCFWriteStreamTypeID, void, stream, "_scheduleInCFRunLoop:forMode:", runLoop, runLoopMode);
1346 _CFStreamScheduleWithRunLoop((struct _CFStream *)stream, runLoop, runLoopMode);
1347 }
1348
1349
1350 __private_extern__ void _CFStreamUnscheduleFromRunLoop(struct _CFStream *stream, CFRunLoopRef runLoop, CFStringRef runLoopMode) {
1351 const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
1352 if (!stream->client) return;
1353 if (!stream->client->rlSource) return;
1354
1355 if (!__CFBitIsSet(stream->flags, SHARED_SOURCE)) {
1356 CFRunLoopRemoveSource(runLoop, stream->client->rlSource, runLoopMode);
1357 } else {
1358 CFArrayRef runLoopAndSourceKey;
1359 CFMutableArrayRef list;
1360 CFIndex c, i;
1361
1362 __CFSpinLock(&sSourceLock);
1363
1364 runLoopAndSourceKey = (CFArrayRef)CFDictionaryGetValue(sSharedSources, stream);
1365 list = (CFMutableArrayRef)CFDictionaryGetValue(sSharedSources, runLoopAndSourceKey);
1366
1367 c = CFArrayGetCount(list);
1368 i = CFArrayGetFirstIndexOfValue(list, CFRangeMake(0, c), stream);
1369 if (i != kCFNotFound) {
1370 CFArrayRemoveValueAtIndex(list, i);
1371 c--;
1372 }
1373
1374 if (!c) {
1375 CFRunLoopRemoveSource(runLoop, stream->client->rlSource, runLoopMode);
1376 CFRunLoopSourceInvalidate(stream->client->rlSource);
1377 CFDictionaryRemoveValue(sSharedSources, runLoopAndSourceKey);
1378 }
1379
1380 CFDictionaryRemoveValue(sSharedSources, stream);
1381
1382 CFRelease(stream->client->rlSource);
1383 stream->client->rlSource = NULL;
1384 __CFBitClear(stream->flags, SHARED_SOURCE);
1385
1386 __CFSpinUnlock(&sSourceLock);
1387 }
1388
1389 _CFStreamRemoveRunLoopAndModeFromArray(stream->client->runLoopsAndModes, runLoop, runLoopMode);
1390
1391 if (cb->unschedule) {
1392 cb->unschedule(stream, runLoop, runLoopMode, _CFStreamGetInfoPointer(stream));
1393 }
1394 }
1395
1396 CF_EXPORT void CFReadStreamUnscheduleFromRunLoop(CFReadStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode) {
1397 CF_OBJC_FUNCDISPATCH2(__kCFReadStreamTypeID, void, stream, "_unscheduleFromCFRunLoop:forMode:", runLoop, runLoopMode);
1398 _CFStreamUnscheduleFromRunLoop((struct _CFStream *)stream, runLoop, runLoopMode);
1399 }
1400
1401 void CFWriteStreamUnscheduleFromRunLoop(CFWriteStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode) {
1402 CF_OBJC_FUNCDISPATCH2(__kCFWriteStreamTypeID, void, stream, "_unscheduleFromCFRunLoop:forMode:", runLoop, runLoopMode);
1403 _CFStreamUnscheduleFromRunLoop((struct _CFStream *)stream, runLoop, runLoopMode);
1404 }
1405
1406 static void waitForOpen(struct _CFStream *stream) {
1407 CFRunLoopRef runLoop = CFRunLoopGetCurrent();
1408 CFStringRef privateMode = CFSTR("_kCFStreamBlockingOpenMode");
1409 _CFStreamScheduleWithRunLoop(stream, runLoop, privateMode);
1410 // 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....
1411 while (__CFStreamGetStatus(stream) == kCFStreamStatusOpening) {
1412 CFRunLoopRunInMode(privateMode, 1e+20, TRUE);
1413 }
1414 _CFStreamUnscheduleFromRunLoop(stream, runLoop, privateMode);
1415 }
1416
1417 CF_INLINE CFArrayRef _CFStreamGetRunLoopsAndModes(struct _CFStream *stream) {
1418 if (stream->client) return stream->client->runLoopsAndModes;
1419 else return NULL;
1420 }
1421
1422 CF_EXPORT CFArrayRef _CFReadStreamGetRunLoopsAndModes(CFReadStreamRef readStream) {
1423 return _CFStreamGetRunLoopsAndModes((struct _CFStream *)readStream);
1424 }
1425
1426 CF_EXPORT CFArrayRef _CFWriteStreamGetRunLoopsAndModes(CFWriteStreamRef writeStream) {
1427 return _CFStreamGetRunLoopsAndModes((struct _CFStream *)writeStream);
1428 }
1429
1430 CF_EXPORT void CFReadStreamSignalEvent(CFReadStreamRef stream, CFStreamEventType event, const void *error) {
1431 _CFStreamSignalEvent((struct _CFStream *)stream, event, (CFErrorRef)error, TRUE);
1432 }
1433
1434 CF_EXPORT void CFWriteStreamSignalEvent(CFWriteStreamRef stream, CFStreamEventType event, const void *error) {
1435 _CFStreamSignalEvent((struct _CFStream *)stream, event, (CFErrorRef)error, TRUE);
1436 }
1437
1438 CF_EXPORT void _CFReadStreamSignalEventDelayed(CFReadStreamRef stream, CFStreamEventType event, const void *error) {
1439 _CFStreamSignalEvent((struct _CFStream *)stream, event, (CFErrorRef)error, FALSE);
1440 }
1441
1442 CF_EXPORT void _CFReadStreamClearEvent(CFReadStreamRef readStream, CFStreamEventType event) {
1443 struct _CFStream *stream = (struct _CFStream *)readStream;
1444 if (stream->client) {
1445 stream->client->whatToSignal &= ~event;
1446 }
1447 }
1448
1449 CF_EXPORT void _CFWriteStreamSignalEventDelayed(CFWriteStreamRef stream, CFStreamEventType event, const void *error) {
1450 _CFStreamSignalEvent((struct _CFStream *)stream, event, (CFErrorRef)error, FALSE);
1451 }
1452
1453 CF_EXPORT void *CFReadStreamGetInfoPointer(CFReadStreamRef stream) {
1454 return _CFStreamGetInfoPointer((struct _CFStream *)stream);
1455 }
1456
1457 CF_EXPORT void *CFWriteStreamGetInfoPointer(CFWriteStreamRef stream) {
1458 return _CFStreamGetInfoPointer((struct _CFStream *)stream);
1459 }
1460
1461 /* CF_EXPORT */
1462 void _CFStreamSourceScheduleWithRunLoop(CFRunLoopSourceRef source, CFMutableArrayRef runLoopsAndModes, CFRunLoopRef runLoop, CFStringRef runLoopMode)
1463 {
1464 CFIndex count;
1465 CFRange range;
1466
1467 count = CFArrayGetCount(runLoopsAndModes);
1468 range = CFRangeMake(0, count);
1469
1470 while (range.length) {
1471
1472 CFIndex i = CFArrayGetFirstIndexOfValue(runLoopsAndModes, range, runLoop);
1473
1474 if (i == kCFNotFound)
1475 break;
1476
1477 if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes, i + 1), runLoopMode))
1478 return;
1479
1480 range.location = i + 2;
1481 range.length = count - range.location;
1482 }
1483
1484 // Add the new values.
1485 CFArrayAppendValue(runLoopsAndModes, runLoop);
1486 CFArrayAppendValue(runLoopsAndModes, runLoopMode);
1487
1488 // Schedule the source on the new loop and mode.
1489 if (source)
1490 CFRunLoopAddSource(runLoop, source, runLoopMode);
1491 }
1492
1493
1494 /* CF_EXPORT */
1495 void _CFStreamSourceUnscheduleFromRunLoop(CFRunLoopSourceRef source, CFMutableArrayRef runLoopsAndModes, CFRunLoopRef runLoop, CFStringRef runLoopMode)
1496 {
1497 CFIndex count;
1498 CFRange range;
1499
1500 count = CFArrayGetCount(runLoopsAndModes);
1501 range = CFRangeMake(0, count);
1502
1503 while (range.length) {
1504
1505 CFIndex i = CFArrayGetFirstIndexOfValue(runLoopsAndModes, range, runLoop);
1506
1507 // If not found, it's not scheduled on it.
1508 if (i == kCFNotFound)
1509 return;
1510
1511 // Make sure it is scheduled in this mode.
1512 if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes, i + 1), runLoopMode)) {
1513
1514 // Remove mode and runloop from the list.
1515 CFArrayReplaceValues(runLoopsAndModes, CFRangeMake(i, 2), NULL, 0);
1516
1517 // Remove it from the runloop.
1518 if (source)
1519 CFRunLoopRemoveSource(runLoop, source, runLoopMode);
1520
1521 return;
1522 }
1523
1524 range.location = i + 2;
1525 range.length = count - range.location;
1526 }
1527 }
1528
1529
1530 /* CF_EXPORT */
1531 void _CFStreamSourceScheduleWithAllRunLoops(CFRunLoopSourceRef source, CFArrayRef runLoopsAndModes)
1532 {
1533 CFIndex i, count = CFArrayGetCount(runLoopsAndModes);
1534
1535 if (!source)
1536 return;
1537
1538 for (i = 0; i < count; i += 2) {
1539
1540 // Make sure it's scheduled on all the right loops and modes.
1541 // Go through the array adding the source to all loops and modes.
1542 CFRunLoopAddSource((CFRunLoopRef)CFArrayGetValueAtIndex(runLoopsAndModes, i),
1543 source,
1544 (CFStringRef)CFArrayGetValueAtIndex(runLoopsAndModes, i + 1));
1545 }
1546 }
1547
1548
1549 /* CF_EXPORT */
1550 void _CFStreamSourceUncheduleFromAllRunLoops(CFRunLoopSourceRef source, CFArrayRef runLoopsAndModes)
1551 {
1552 CFIndex i, count = CFArrayGetCount(runLoopsAndModes);
1553
1554 if (!source)
1555 return;
1556
1557 for (i = 0; i < count; i += 2) {
1558
1559 // Go through the array removing the source from all loops and modes.
1560 CFRunLoopRemoveSource((CFRunLoopRef)CFArrayGetValueAtIndex(runLoopsAndModes, i),
1561 source,
1562 (CFStringRef)CFArrayGetValueAtIndex(runLoopsAndModes, i + 1));
1563 }
1564 }
1565
1566 Boolean _CFStreamRemoveRunLoopAndModeFromArray(CFMutableArrayRef runLoopsAndModes, CFRunLoopRef rl, CFStringRef mode) {
1567 CFIndex idx, cnt;
1568 Boolean found = FALSE;
1569
1570 if (!runLoopsAndModes) return FALSE;
1571
1572 cnt = CFArrayGetCount(runLoopsAndModes);
1573 for (idx = 0; idx + 1 < cnt; idx += 2) {
1574 if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes, idx), rl) && CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes, idx + 1), mode)) {
1575 CFArrayRemoveValueAtIndex(runLoopsAndModes, idx);
1576 CFArrayRemoveValueAtIndex(runLoopsAndModes, idx);
1577 found = TRUE;
1578 break;
1579 }
1580 }
1581 return found;
1582 }
1583
1584 // Used by NSStream to properly allocate the bridged objects
1585 CF_EXPORT CFIndex _CFStreamInstanceSize(void) {
1586 return sizeof(struct _CFStream);
1587 }
1588
1589 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1590 #elif DEPLOYMENT_TARGET_WINDOWS
1591 void __CFStreamCleanup(void) {
1592 __CFSpinLock(&sSourceLock);
1593 if (sSharedSources) {
1594 CFIndex count = CFDictionaryGetCount(sSharedSources);
1595 if (count == 0) {
1596 // Only release if empty. If it's still holding streams (which would be a client
1597 // bug leak), freeing this dict would free the streams, which then need to access the
1598 // dict to remove themselves, which leads to a deadlock.
1599 CFRelease(sSharedSources);
1600 sSharedSources = NULL;
1601 } else {
1602 const void ** keys = (const void **)malloc(sizeof(const void *) * count);
1603 #if defined(DEBUG)
1604 int i;
1605 #endif
1606 CFDictionaryGetKeysAndValues(sSharedSources, keys, NULL);
1607 fprintf(stderr, "*** CFNetwork is shutting down, but %ld streams are still scheduled.\n", count);
1608 #if defined(DEBUG)
1609 for (i = 0; i < count;i ++) {
1610 if ((CFGetTypeID(keys[i]) == __kCFReadStreamTypeID) || (CFGetTypeID(keys[i]) == __kCFWriteStreamTypeID)) {
1611 CFShow(keys[i]);
1612 }
1613 }
1614 #endif
1615 }
1616 }
1617 __CFSpinUnlock(&sSourceLock);
1618 }
1619 #else
1620 #error Unknown or unspecified DEPLOYMENT_TARGET
1621 #endif
1622