Example #1
0
static void MyCFWriteStreamClientCallBack(CFWriteStreamRef stream, CFStreamEventType type, void *clientCallBackInfo)
{
	MyStreamInfoPtr	myInfoPtr = (MyStreamInfoPtr) clientCallBackInfo;
	
	printf("MyCFWriteStreamClientCallBack entered - event is %d\n", (int) type);
	
	switch (type)
	{
		case kCFStreamEventOpenCompleted:
			myInfoPtr->isConnected = TRUE;
			TestGetIFAddrs();		// call the test function to return the local ip address associated with this connection.
			if (myInfoPtr->clientCB)
			{
				// call client callback routine
				myInfoPtr->clientCB(myInfoPtr->refCon);
			}
			printf("write stream connected\n");
			break;
			
		case kCFStreamEventErrorOccurred:
			myInfoPtr->errorOccurred = TRUE;
			myInfoPtr->error = CFWriteStreamGetError(myInfoPtr->wStreamRef);
			printf("write stream error %d .. giving up\n", (int)myInfoPtr->error.error);
			break;
			
		default:
			break;
	}
	// stop the run loop at this point
	CFRunLoopStop(CFRunLoopGetCurrent());
}
Example #2
0
void SocketStreamHandle::writeStreamCallback(CFStreamEventType type)
{
    switch(type) {
    case kCFStreamEventNone:
        break;
    case kCFStreamEventOpenCompleted:
        break;
    case kCFStreamEventHasBytesAvailable:
        ASSERT_NOT_REACHED();
        break;
    case kCFStreamEventCanAcceptBytes: {
        // Possibly, a spurious event from CONNECT handshake.
        if (!CFWriteStreamCanAcceptBytes(m_writeStream.get()))
            return;

        if (m_connectingSubstate == WaitingForCredentials)
            break;

        if (m_connectingSubstate == WaitingForConnect) {
            m_connectingSubstate = Connected;
            m_state = Open;

            RefPtr<SocketStreamHandle> protect(this); // The client can close the handle, potentially removing the last reference.
            m_client->didOpen(this);
            break;
        }

        ASSERT(m_state == Open);
        ASSERT(m_connectingSubstate == Connected);

        sendPendingData();
        break;
    }
    case kCFStreamEventErrorOccurred: {
#ifndef BUILDING_ON_TIGER
        RetainPtr<CFErrorRef> error(AdoptCF, CFWriteStreamCopyError(m_writeStream.get()));
        reportErrorToClient(error.get());
#else
        CFStreamError error = CFWriteStreamGetError(m_writeStream.get());
        m_client->didFail(this, SocketStreamError(error.error)); // FIXME: Provide a sensible error.
#endif
        break;
    }
    case kCFStreamEventEndEncountered:
        // FIXME: Currently, we handle closing in read callback, but these can come independently (e.g. a server can stop listening, but keep sending data).
        break;
    }
}
Example #3
0
ssize_t SSLImpl::send(const void *mem, size_t len, void *storage)
{
    ssl_data_t *data = (ssl_data_t*)storage;
    
    if (!CFWriteStreamCanAcceptBytes(data->writeStream))
        return 0;
    
    int rc = CFWriteStreamWrite(data->writeStream, (const UInt8 *)mem, len);
    if (rc < 0) {
        CFStreamError err = CFWriteStreamGetError(data->writeStream);
        report_error("SSL send failed", &err);
        return -1;
    }
    
    return rc;
}
Example #4
0
/* MyUploadCallBack is the stream callback for the CFFTPStream during an upload operation. 
Its main purpose is to wait for space to become available in the FTP stream (the write stream), 
and then read bytes from the file stream (the read stream) and write them to the FTP stream. */
static void
MyUploadCallBack(CFWriteStreamRef writeStream, CFStreamEventType type, void * clientCallBackInfo)
{
    MyStreamInfo     *info = (MyStreamInfo *)clientCallBackInfo;
    CFIndex          bytesRead;
    CFIndex          bytesAvailable;
    CFIndex          bytesWritten;
    CFStreamError    error;
    
    assert(writeStream != NULL);
    assert(info        != NULL);
    assert(info->writeStream == writeStream);

    switch (type) {

        case kCFStreamEventOpenCompleted:
            fprintf(stderr, "Open complete\n");
            break;
        case kCFStreamEventCanAcceptBytes:

            /* The first thing we do is check to see if there's some leftover data that we read
            in a previous callback, which we were unable to upload for whatever reason. */
            if (info->leftOverByteCount > 0) {
                bytesRead = 0;
                bytesAvailable = info->leftOverByteCount;
            } else {
                /* If not, we try to read some more data from the file.  CFReadStreamRead will 
                return the number of bytes read, or -1 if an error occurs preventing 
                any bytes from being read, or 0 if the stream's end was encountered. */
                bytesRead = CFReadStreamRead(info->readStream, info->buffer, kMyBufferSize);
                if (bytesRead < 0) {
                    fprintf(stderr, "CFReadStreamRead returned %ld\n", bytesRead);
                    goto exit;
                }
                bytesAvailable = bytesRead;
            }
//            bytesWritten = 0;
            
            if (bytesAvailable == 0) {
                /* We've hit the end of the file being uploaded.  Shut everything down. 
                Previous versions of this sample would terminate the upload stream 
                by writing zero bytes to the stream.  After discussions with CF engineering, 
                we've decided that it's better to terminate the upload stream by just 
                closing the stream. */
                fprintf(stderr, "\nEnd up uploaded file; closing down\n");
                goto exit;
            } else {

                /* CFWriteStreamWrite returns the number of bytes successfully written, -1 if an error has
                occurred, or 0 if the stream has been filled to capacity (for fixed-length streams).
                If the stream is not full, this call will block until at least one byte is written. 
                However, as we're in the kCFStreamEventCanAcceptBytes callback, we know that at least 
                one byte can be written, so we won't block. */

                bytesWritten = CFWriteStreamWrite(info->writeStream, info->buffer, bytesAvailable);
                if (bytesWritten > 0) {

                    info->totalBytesWritten += bytesWritten;
                    
                    /* If we couldn't upload all the data that we read, we temporarily store the data in our MyStreamInfo
                    context until our CFWriteStream callback is called again with a kCFStreamEventCanAcceptBytes event. 
                    Copying the data down inside the buffer is not the most efficient approach, but it makes the code 
                    significantly easier. */
                    if (bytesWritten < bytesAvailable) {
                        info->leftOverByteCount = bytesAvailable - bytesWritten;
                        memmove(info->buffer, info->buffer + bytesWritten, info->leftOverByteCount);
                    } else {
                        info->leftOverByteCount = 0;
                    }
                } else if (bytesWritten < 0) {
                    fprintf(stderr, "CFWriteStreamWrite returned %ld\n", bytesWritten);
                    /* If CFWriteStreamWrite failed, the write stream is dead.  We will clean up 
                    when we get kCFStreamEventErrorOccurred. */
                }
            }
            
            /* Print a status update if we made any forward progress. */
            if ( (bytesRead > 0) || (bytesWritten > 0) ) {
                fprintf(stderr, "\rRead %7ld bytes; Wrote %8ld bytes", bytesRead, info->totalBytesWritten);
            }
            break;
        case kCFStreamEventErrorOccurred:
            error = CFWriteStreamGetError(info->writeStream);
            fprintf(stderr, "CFReadStreamGetError returned (%ld, %ld)\n", error.domain, error.error);
            goto exit;
        case kCFStreamEventEndEncountered:
            fprintf(stderr, "\nUpload complete\n");
            goto exit;
        default:
            fprintf(stderr, "Received unexpected CFStream event (%ld)", type);
            break;
    }
    return;
    
exit:
    MyStreamInfoDestroy(info);
    CFRunLoopStop(CFRunLoopGetCurrent());
    return;
}