Re: CFStream bugs? (was Re: CFNetwork Website)
Re: CFStream bugs? (was Re: CFNetwork Website)
- Subject: Re: CFStream bugs? (was Re: CFNetwork Website)
- From: Becky Willrich <email@hidden>
- Date: Thu, 23 May 2002 10:06:03 -0700
The [CFStream] API contained numerous bugs in Mac OS X 10.1.x.
Does anyone know what the bugs are or their severity? If I were to make my server program use them, are they inconveniences or major crashers?
The short answer is that the bugs that have been fixed are serious, but once you know they're there, they can all be worked around fairly easily. Here's my understanding of the worst issues in 10.1.x and their workarounds:
- A stream may invoke the client's event handler from within a call to CFReadStreamRead/CFWriteStreamWrite. Workaround is for the client to be prepared for re-entrancy. You can also SetClient(NULL) immediately before calling Read/Write, then restore the client after the call returns, but if you do this, you must check for end-of-stream and error immediately after Read/Write returns - you will have lost the event.
- CFReadStreamRead occasionally returns 0 when the stream is not AtEnd. Workaround is just to check the stream's status if 0 has been returned; the stream will correctly report its status as either AtEnd or Open, depending on whether the stream has truly reached its end
- If CFReadStreamRead returns 0 or -1, occasionally the matching AtEnd event or ErrorOccurred event is not sent. Workaround is to make sure and properly field those return values.
- There is a race condition such that if you call CFReadStreamRead() multiple times in response to a HasBytesAvailable event, you might get another HasBytesAvailable event even though there are no further bytes to be read. Workaround is to either always call CFReadStreamRead() only once in response to kCFStreamEventHasBytesAvailable, or always call CFReadStreamHasBytesAvailable() (which will correctly return TRUE only if bytes are actually there) explicitly before calling CFReadStreamRead().
The above bugs mean there's a "golden path" to implementing your callback (assuming you're using the stream in an event-based fashion). Your callback should look something like this (caveats: I haven't tried to compile this, so look out for typos. Also, this assumes that there's only one stream being managed; if you're handling multiple streams through the same callback, you will need to set the inReadStreamRead flag in a per-stream fashion):
handleStreamEvent(...) {
switch(eventType) {
case kCFStreamEventHasBytesAvailable:
inReadStreamRead = TRUE;
bytesRead = CFReadStreamRead(stream, buffer, bufSize);
inReadStreamRead = FALSE;
if (bytesRead < 0) {
handleError();
} else if (bytesRead == 0 && CFReadStreamGetStatus(stream) == kCFStreamStatusAtEnd) {
handleEndOfStream();
} else {
handleBytes(buffer, bytesRead);
}
break;
case kCFStreamEventErrorOccurred:
if (!inReadStreamRead)
handleError();
break;
case kCFStreamEventEndEncountered:
if (!inReadStreamRead)
handleEndOfStream();
break;
....
}
- Socket write streams block for the entire write. Note that this isn't a problem unless there's a danger of overflowing the kernel's socket buffer (32K by default). There's no complete workaround for this, but you can mitigate it almost completely by writing in relatively small chunks (small multiples of K at a time), and only if either a kCFStreamEventCanAcceptBytes has arrived or if CFWriteStreamCanAcceptBytes returns TRUE. Basically, you're insuring that the kernel has some space in the buffer when you write, and are trying to write small enough numbers of bytes that the kernel has had time to transmit at least that much data. Or you can just be prepared for CFWriteStreamWrite to block.
- Secure socket streams are not thread-safe. Workaround is to manage all secure socket streams on a single thread (preferably via the run loop), or to lock. Note that this includes https streams.
- All streams that need to do address resolution block for the length of that resolution; this usually is insignificant, but if something has caused the core OS DNS daemon to crash, this can be a very long hang (> 1 minute). Workaround is to either do the DNS resolution yourself and provide CFNetwork/CFStream with the resolved IP address in place of the hostname, or to put all streams on a thread where the block will do no harm.
- Hostnames that start with digits are not properly resolved; workaround is to detect the situation and do the resolution yourself, then give CFNetwork/CFStream the resolved IP address in place of the hostname.
I think that covers it, but of course, I may have forgotten something.
Hope that helps,
REW
_______________________________________________
macnetworkprog mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/macnetworkprog
Do not post admin requests to the list. They will be ignored.