bool HTTP_Stream::open(const HTTP_Stream_Position& position) { bool success = false; CFStreamClientContext CTX = { 0, this, NULL, NULL, NULL }; /* Already opened a read stream, return */ if (m_readStream) { goto out; } /* Reset state */ m_position = position; m_readPending = false; m_httpHeadersParsed = false; m_contentType = ""; m_icyStream = false; m_icyHeaderCR = false; m_icyHeadersRead = false; m_icyHeadersParsed = false; m_icyHeaderLines.clear(); m_icyMetaDataInterval = 0; m_dataByteReadCount = 0; m_metaDataBytesRemaining = 0; if (!m_url) { goto out; } /* Failed to create a stream */ if (!(m_readStream = createReadStream(m_url))) { goto out; } if (!CFReadStreamSetClient(m_readStream, kCFStreamEventHasBytesAvailable | kCFStreamEventEndEncountered | kCFStreamEventErrorOccurred, readCallBack, &CTX)) { CFRelease(m_readStream), m_readStream = 0; goto out; } setScheduledInRunLoop(true); if (!CFReadStreamOpen(m_readStream)) { /* Open failed: clean */ CFReadStreamSetClient(m_readStream, 0, NULL, NULL); setScheduledInRunLoop(false); if (m_readStream) { CFRelease(m_readStream), m_readStream = 0; } goto out; } success = true; out: return success; }
static void FetchIPAddress() { if(publicIPState == IPStateFetching) return; publicIPState = IPStateFetching; const UInt8 bodyBytes[] = {0}; CFDataRef body = CFDataCreate(kCFAllocatorDefault, bodyBytes, 0); CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault, CFSTR("http://icanhazip.com"), NULL); CFHTTPMessageRef request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("GET"), url, kCFHTTPVersion1_1); CFHTTPMessageSetBody(request, body); #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" // Apple suggests the NSURLSession API instead of CFReadStreamCreateForHTTPRequest, // But obviously that doesn't really work here CFReadStreamRef stream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, request); #pragma clang diagnostic pop CFRelease(body); CFRelease(url); CFRelease(request); CFMutableDataRef responseData = CFDataCreateMutable(kCFAllocatorDefault, 17); CFStreamClientContext context = { 0, responseData, NULL, NULL, NULL }; if(!CFReadStreamSetClient(stream, kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable | kCFStreamEventEndEncountered | kCFStreamEventErrorOccurred, &IPStreamCallback, &context)) { CFRelease(stream); publicIPState = IPStateInvalid; return; } // Add to the run loop and open the stream CFReadStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); if(!CFReadStreamOpen(stream)) { CFReadStreamSetClient(stream, 0, NULL, NULL); CFReadStreamUnscheduleFromRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); CFRelease(stream); publicIPState = IPStateInvalid; return; } // Run the run loop do { CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0, TRUE); } while(publicIPState == IPStateFetching); }
void SocketStreamHandle::scheduleStreams() { ASSERT(m_readStream); ASSERT(m_writeStream); CFStreamClientContext clientContext = { 0, this, 0, 0, copyCFStreamDescription }; // FIXME: Pass specific events we're interested in instead of -1. CFReadStreamSetClient(m_readStream.get(), static_cast<CFOptionFlags>(-1), readStreamCallback, &clientContext); CFWriteStreamSetClient(m_writeStream.get(), static_cast<CFOptionFlags>(-1), writeStreamCallback, &clientContext); #if PLATFORM(WIN) CFReadStreamScheduleWithRunLoop(m_readStream.get(), loaderRunLoop(), kCFRunLoopDefaultMode); CFWriteStreamScheduleWithRunLoop(m_writeStream.get(), loaderRunLoop(), kCFRunLoopDefaultMode); #else CFReadStreamScheduleWithRunLoop(m_readStream.get(), CFRunLoopGetCurrent(), kCFRunLoopCommonModes); CFWriteStreamScheduleWithRunLoop(m_writeStream.get(), CFRunLoopGetCurrent(), kCFRunLoopCommonModes); #endif CFReadStreamOpen(m_readStream.get()); CFWriteStreamOpen(m_writeStream.get()); #ifndef BUILDING_ON_TIGER if (m_pacRunLoopSource) removePACRunLoopSource(); #endif m_connectingSubstate = WaitingForConnect; }
/* MyStreamInfoDestroy destroys a MyStreamInfo 'object', cleaning up any resources that it owns. */ static void MyStreamInfoDestroy(MyStreamInfo * info) { assert(info != NULL); if (info->readStream) { CFReadStreamUnscheduleFromRunLoop(info->readStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); (void) CFReadStreamSetClient(info->readStream, kCFStreamEventNone, NULL, NULL); /* CFReadStreamClose terminates the stream. */ CFReadStreamClose(info->readStream); CFRelease(info->readStream); } if (info->writeStream) { CFWriteStreamUnscheduleFromRunLoop(info->writeStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); (void) CFWriteStreamSetClient(info->writeStream, kCFStreamEventNone, NULL, NULL); /* CFWriteStreamClose terminates the stream. */ CFWriteStreamClose(info->writeStream); CFRelease(info->writeStream); } if (info->proxyDict) { CFRelease(info->proxyDict); // see discussion of <rdar://problem/3745574> below } free(info); }
static void advanceCurrentStream(FormStreamFields *form) { closeCurrentStream(form); if (form->remainingElements.isEmpty()) return; // Create the new stream. FormDataElement& nextInput = form->remainingElements.last(); if (nextInput.m_type == FormDataElement::data) { size_t size = nextInput.m_data.size(); char* data = nextInput.m_data.releaseBuffer(); form->currentStream = CFReadStreamCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(data), size, kCFAllocatorNull); form->currentData = data; } else { CFStringRef filename = nextInput.m_filename.createCFString(); #if PLATFORM(WIN) CFURLRef fileURL = CFURLCreateWithFileSystemPath(0, filename, kCFURLWindowsPathStyle, FALSE); #else CFURLRef fileURL = CFURLCreateWithFileSystemPath(0, filename, kCFURLPOSIXPathStyle, FALSE); #endif CFRelease(filename); form->currentStream = CFReadStreamCreateWithFile(0, fileURL); CFRelease(fileURL); } form->remainingElements.removeLast(); // Set up the callback. CFStreamClientContext context = { 0, form, NULL, NULL, NULL }; CFReadStreamSetClient(form->currentStream, kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, formEventCallback, &context); // Schedule with the current set of run loops. CFSetApplyFunction(form->scheduledRunLoopPairs, scheduleWithPair, form->currentStream); }
bool HTTPInputSource::Open(CFErrorRef *error) { if(IsOpen()) { LOGGER_WARNING("org.sbooth.AudioEngine.InputSource.HTTP", "Open() called on an InputSource that is already open"); return true; } // Set up the HTTP request mRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("GET"), mURL, kCFHTTPVersion1_1); if(NULL == mRequest) { if(error) *error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainPOSIX, ENOMEM, NULL); return false; } CFHTTPMessageSetHeaderFieldValue(mRequest, CFSTR("User-Agent"), CFSTR("SFBAudioEngine")); // Seek support if(0 < mDesiredOffset) { CFStringRef byteRange = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("bytes=%ld-"), mDesiredOffset); CFHTTPMessageSetHeaderFieldValue(mRequest, CFSTR("Range"), byteRange); CFRelease(byteRange), byteRange = NULL; } mReadStream = CFReadStreamCreateForStreamedHTTPRequest(kCFAllocatorDefault, mRequest, NULL); if(NULL == mReadStream) { CFRelease(mRequest), mRequest = NULL; if(error) *error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainPOSIX, ENOMEM, NULL); return false; } // Start the HTTP connection CFStreamClientContext myContext = { 0, this, NULL, NULL, NULL }; CFOptionFlags clientFlags = kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered; if(!CFReadStreamSetClient(mReadStream, clientFlags, myCFReadStreamClientCallBack, &myContext)) { CFRelease(mRequest), mRequest = NULL; CFRelease(mReadStream), mReadStream = NULL; if(error) *error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainPOSIX, ENOMEM, NULL); return false; } CFReadStreamScheduleWithRunLoop(mReadStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); if(!CFReadStreamOpen(mReadStream)) { CFRelease(mRequest), mRequest = NULL; CFRelease(mReadStream), mReadStream = NULL; if(error) *error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainPOSIX, ENOMEM, NULL); return false; } while(NULL == mResponseHeaders) CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); mIsOpen = true; return true; }
static void asynchttp_complete(asynchttp_t *http) { secdebug("http", "http: %p", http); /* Shutdown streams and timer, we're about to invoke our client callback. */ if (http->stream) { CFReadStreamSetClient(http->stream, kCFStreamEventNone, NULL, NULL); CFReadStreamSetDispatchQueue(http->stream, NULL); CFReadStreamClose(http->stream); CFReleaseNull(http->stream); } if (http->timer) { dispatch_source_cancel(http->timer); dispatch_release_null(http->timer); } if (http->completed) { /* This should probably move to our clients. */ CFTimeInterval maxAge = NULL_TIME; if (http->response) { CFStringRef cacheControl = CFHTTPMessageCopyHeaderFieldValue( http->response, CFSTR("cache-control")); if (cacheControl) { CFStringRef maxAgeValue = copyParseMaxAge(cacheControl); CFRelease(cacheControl); if (maxAgeValue) { secdebug("http", "http header max-age: %@", maxAgeValue); maxAge = CFStringGetDoubleValue(maxAgeValue); CFRelease(maxAgeValue); } } } http->completed(http, maxAge); } }
/* extern */ void _CFTypeInvalidate(CFTypeRef obj) { CFTypeID t = CFGetTypeID(obj); /* Invalidate according to type of object. */ if (t == CFRunLoopSourceGetTypeID()) { CFRunLoopSourceInvalidate((CFRunLoopSourceRef)obj); } else if (t == CFMachPortGetTypeID()) { CFMachPortInvalidate((CFMachPortRef)obj); } else if (t == CFSocketGetTypeID()) { CFSocketInvalidate((CFSocketRef)obj); } /* For scheduled types of objects, it is invalidated by setting the client to NULL. */ else if (t == CFReadStreamGetTypeID()) { CFReadStreamSetClient((CFReadStreamRef)obj, kCFStreamEventNone, NULL, NULL); } else if (t == CFWriteStreamGetTypeID()) { CFWriteStreamSetClient((CFWriteStreamRef)obj, kCFStreamEventNone, NULL, NULL); } else if (t == CFHostGetTypeID()) { CFHostSetClient((CFHostRef)obj, NULL, NULL); } else if (t == SCNetworkReachabilityGetTypeID()) { SCNetworkReachabilitySetCallback((SCNetworkReachabilityRef)obj, NULL, NULL); } else if (t == CFRunLoopTimerGetTypeID()) { CFRunLoopTimerInvalidate((CFRunLoopTimerRef)obj); } else if (t == CFNetServiceGetTypeID()) { CFNetServiceSetClient((CFNetServiceRef)obj, NULL, NULL); } else if (t == CFNetServiceBrowserGetTypeID()) { CFNetServiceBrowserInvalidate((CFNetServiceBrowserRef)obj); } else if (t == CFNetServiceMonitorGetTypeID()) { CFNetServiceMonitorInvalidate((CFNetServiceMonitorRef)obj); } else if (t == SCNetworkReachabilityGetTypeID()) { SCNetworkConnectionStop((SCNetworkConnectionRef)obj, FALSE); } }
static void closeCurrentStream(FormStreamFields* form) { if (form->currentStream) { CFReadStreamClose(form->currentStream); CFReadStreamSetClient(form->currentStream, kCFStreamEventNone, 0, 0); CFRelease(form->currentStream); form->currentStream = 0; form->currentStreamRangeLength = BlobDataItem::toEndOfFile; } form->currentData = nullptr; }
void HTTP_Stream::close() { /* The stream has been already closed */ if (!m_readStream) { return; } CFReadStreamSetClient(m_readStream, 0, NULL, NULL); setScheduledInRunLoop(false); CFReadStreamClose(m_readStream); CFRelease(m_readStream), m_readStream = 0; }
// Return false if we cannot advance the stream. Currently the only possible failure is that the underlying file has been removed or changed since File.slice. static bool advanceCurrentStream(FormStreamFields* form) { closeCurrentStream(form); if (form->remainingElements.isEmpty()) return true; // Create the new stream. FormDataElement& nextInput = form->remainingElements.last(); if (nextInput.m_type == FormDataElement::data) { size_t size = nextInput.m_data.size(); MallocPtr<char> data = nextInput.m_data.releaseBuffer(); form->currentStream = CFReadStreamCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(data.get()), size, kCFAllocatorNull); form->currentData = std::move(data); } else { #if ENABLE(BLOB) // Check if the file has been changed or not if required. if (isValidFileTime(nextInput.m_expectedFileModificationTime)) { time_t fileModificationTime; if (!getFileModificationTime(nextInput.m_filename, fileModificationTime) || fileModificationTime != static_cast<time_t>(nextInput.m_expectedFileModificationTime)) return false; } #endif const String& path = nextInput.m_shouldGenerateFile ? nextInput.m_generatedFilename : nextInput.m_filename; form->currentStream = CFReadStreamCreateWithFile(0, pathAsURL(path).get()); if (!form->currentStream) { // The file must have been removed or become unreadable. return false; } #if ENABLE(BLOB) if (nextInput.m_fileStart > 0) { RetainPtr<CFNumberRef> position = adoptCF(CFNumberCreate(0, kCFNumberLongLongType, &nextInput.m_fileStart)); CFReadStreamSetProperty(form->currentStream, kCFStreamPropertyFileCurrentOffset, position.get()); } form->currentStreamRangeLength = nextInput.m_fileLength; #endif } form->remainingElements.removeLast(); // Set up the callback. CFStreamClientContext context = { 0, form, 0, 0, 0 }; CFReadStreamSetClient(form->currentStream, kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, formEventCallback, &context); // Schedule with the current set of run loops. SchedulePairHashSet::iterator end = form->scheduledRunLoopPairs.end(); for (SchedulePairHashSet::iterator it = form->scheduledRunLoopPairs.begin(); it != end; ++it) CFReadStreamScheduleWithRunLoop(form->currentStream, (*it)->runLoop(), (*it)->mode()); return true; }
static void closeCurrentStream(FormStreamFields *form) { if (form->currentStream) { CFReadStreamClose(form->currentStream); CFReadStreamSetClient(form->currentStream, kCFStreamEventNone, NULL, NULL); CFRelease(form->currentStream); form->currentStream = NULL; } if (form->currentData) { fastFree(form->currentData); form->currentData = 0; } }
static void closeCurrentStream(FormStreamFields* form) { ASSERT(form->streamIsBeingOpenedOrClosedLock.isHeld()); if (form->currentStream) { CFReadStreamClose(form->currentStream); CFReadStreamSetClient(form->currentStream, kCFStreamEventNone, 0, 0); CFRelease(form->currentStream); form->currentStream = 0; form->currentStreamRangeLength = BlobDataItem::toEndOfFile; } form->currentData = nullptr; }
/* MySimpleDirectoryListing implements the directory list command. It sets up a MyStreamInfo 'object' with the read stream being an FTP stream of the directory to list and with no write stream. It then returns, and the real work happens asynchronously in the runloop. The function returns true if the stream setup succeeded, and false if it failed. */ static Boolean MySimpleDirectoryListing(CFStringRef urlString, CFStringRef username, CFStringRef password) { CFReadStreamRef readStream; CFStreamClientContext context = { 0, NULL, NULL, NULL, NULL }; CFURLRef downloadURL; Boolean success = true; MyStreamInfo *streamInfo; assert(urlString != NULL); downloadURL = CFURLCreateWithString(kCFAllocatorDefault, urlString, NULL); assert(downloadURL != NULL); /* Create an FTP read stream for downloading operation from an FTP URL. */ readStream = CFReadStreamCreateWithFTPURL(kCFAllocatorDefault, downloadURL); assert(readStream != NULL); CFRelease(downloadURL); /* Initialize our MyStreamInfo structure, which we use to store some information about the stream. */ MyStreamInfoCreate(&streamInfo, readStream, NULL); context.info = (void *)streamInfo; /* CFReadStreamSetClient registers a callback to hear about interesting events that occur on a stream. */ success = CFReadStreamSetClient(readStream, kNetworkEvents, MyDirectoryListingCallBack, &context); if (success) { /* Schedule a run loop on which the client can be notified about stream events. The client callback will be triggered via the run loop. It's the caller's responsibility to ensure that the run loop is running. */ CFReadStreamScheduleWithRunLoop(readStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); MyCFStreamSetUsernamePassword(readStream, username, password); MyCFStreamSetFTPProxy(readStream, &streamInfo->proxyDict); /* CFReadStreamOpen will return success/failure. Opening a stream causes it to reserve all the system resources it requires. If the stream can open non-blocking, this will always return TRUE; listen to the run loop source to find out when the open completes and whether it was successful. */ success = CFReadStreamOpen(readStream); if (success == false) { fprintf(stderr, "CFReadStreamOpen failed\n"); MyStreamInfoDestroy(streamInfo); } } else { fprintf(stderr, "CFReadStreamSetClient failed\n"); MyStreamInfoDestroy(streamInfo); } return success; }
static void cfstream_data_close(struct mailstream_cfstream_data * cfstream_data) { if (cfstream_data->writeStream != NULL) { CFWriteStreamSetClient(cfstream_data->writeStream, kCFStreamEventNone, NULL, NULL); CFWriteStreamClose(cfstream_data->writeStream); CFRelease(cfstream_data->writeStream); cfstream_data->writeStream = NULL; } if (cfstream_data->readStream != NULL) { CFReadStreamSetClient(cfstream_data->readStream, kCFStreamEventNone, NULL, NULL); CFReadStreamClose(cfstream_data->readStream); CFRelease(cfstream_data->readStream); cfstream_data->readStream = NULL; } }
static void IPStreamCallback(CFReadStreamRef stream, CFStreamEventType eventType, void *clientCallBackInfo) { CFMutableDataRef responseData = (CFMutableDataRef)clientCallBackInfo; if(eventType & kCFStreamEventHasBytesAvailable) { UInt8 buffer[1024]; CFIndex read; do { read = CFReadStreamRead(stream, buffer, sizeof(buffer)); if(read > 0) CFDataAppendBytes(responseData, buffer, read); } while(read > 0); } if(eventType & (kCFStreamEventEndEncountered | kCFStreamEventErrorOccurred)) { if((eventType & kCFStreamEventEndEncountered) && publicIPState == IPStateFetching) { if(publicIPData) CFRelease(publicIPData); publicIPData = CFDataCreateCopy(kCFAllocatorDefault, responseData); publicIPState = IPStateFetched; } if(eventType & kCFStreamEventErrorOccurred) { if(publicIPData) CFRelease(publicIPData); publicIPData = NULL; publicIPState = IPStateInvalid; } CFReadStreamClose(stream); CFReadStreamSetClient(stream, 0, NULL, NULL); CFReadStreamUnscheduleFromRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); CFRelease(stream); CFRelease(responseData); } }
bool TCPStream_CFNetwork::connect() { state = Stream::State::Opening; CFStringRef host_cfstring = CFStringCreateWithCString(kCFAllocatorDefault, remoteHostName.c_str(), kCFStringEncodingUTF8); CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, host_cfstring, remotePortNumber, &inputStream, &outputStream); CFRelease(host_cfstring); CFStreamClientContext inputStreamContext; memset(&inputStreamContext, 0, sizeof(inputStreamContext)); inputStreamContext.info = reinterpret_cast<void *>(this); CFReadStreamSetClient(inputStream, kCFStreamEventHasBytesAvailable | kCFStreamEventEndEncountered | kCFStreamEventErrorOccurred, inputStreamCallback, &inputStreamContext); CFReadStreamScheduleWithRunLoop(inputStream, CFRunLoopGetMain(), kCFRunLoopDefaultMode); if (CFReadStreamOpen(inputStream) && CFWriteStreamOpen(outputStream)) { state = Stream::State::Open; return true; } else { CFRelease(outputStream); CFRelease(inputStream); outputStream = nullptr; inputStream = nullptr; state = Stream::State::NotOpen; return false; } }
void HTTPLoader::load(CFURLRef url) { CFHTTPMessageRef request = CFHTTPMessageCreateRequest(NULL, CFSTR("GET"), url, kCFHTTPVersion1_1); mStream = CFReadStreamCreateForHTTPRequest(NULL, request); CFRelease(request); if (!CFReadStreamOpen(mStream)) { CFRelease(mStream); mStream = 0; } else { CFStreamClientContext context = {0, this, NULL, NULL, NULL}; CFReadStreamSetClient(mStream, kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, readStreamCallback, &context); CFReadStreamScheduleWithRunLoop(mStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); } }
/* extern */ void HttpContextClose(HttpContextRef context) { CFRunLoopRef runLoop = CFRunLoopGetCurrent(); // Check if the read stream exists. if (context->_inStream) { // Unschedule, close, and release it. CFReadStreamSetClient(context->_inStream, 0, NULL, NULL); CFReadStreamUnscheduleFromRunLoop(context->_inStream, runLoop, kCFRunLoopCommonModes); CFReadStreamClose(context->_inStream); CFRelease(context->_inStream); // Remove the reference. context->_inStream = NULL; } // Check if the write stream exists. if (context->_outStream) { // Unschedule, close, and release it. CFWriteStreamSetClient(context->_outStream, 0, NULL, NULL); CFWriteStreamUnscheduleFromRunLoop(context->_outStream, runLoop, kCFRunLoopCommonModes); CFWriteStreamClose(context->_outStream); CFRelease(context->_outStream); // Remove the reference. context->_outStream = NULL; } // Get rid of the timer, if it still exists if (context->_timer != NULL) { CFRunLoopTimerInvalidate(context->_timer); CFRelease(context->_timer); context->_timer = NULL; } }
mailstream_low * mailstream_low_cfstream_open_voip_timeout(const char * hostname, int16_t port, int voip_enabled, time_t timeout) { #if HAVE_CFNETWORK mailstream_low * s; struct mailstream_cfstream_data * cfstream_data; CFReadStreamRef readStream; CFWriteStreamRef writeStream; CFStringRef hostString; CFOptionFlags readFlags; CFOptionFlags writeFlags; int r; hostString = CFStringCreateWithCString(NULL, hostname, kCFStringEncodingUTF8); CFStreamCreatePairWithSocketToHost(NULL, hostString, port, &readStream, &writeStream); CFRelease(hostString); #if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR if (voip_enabled) { CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); } #endif cfstream_data = cfstream_data_new(readStream, writeStream); s = mailstream_low_new(cfstream_data, mailstream_cfstream_driver); mailstream_low_set_timeout(s, timeout); //fprintf(stderr, "open %s %i -> %p\n", hostname, port, s); /* setup streams */ cfstream_data->streamContext.info = s; readFlags = kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered; writeFlags = kCFStreamEventOpenCompleted | kCFStreamEventCanAcceptBytes | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered; CFReadStreamSetClient(cfstream_data->readStream, readFlags, readStreamCallback, &cfstream_data->streamContext); CFWriteStreamSetClient(cfstream_data->writeStream, writeFlags, writeStreamCallback, &cfstream_data->streamContext); CFRelease(readStream); CFRelease(writeStream); readStream = NULL; writeStream = NULL; /* setup cancel */ cfstream_data->cancelContext.info = s; cfstream_data->cancelContext.perform = cancelPerform; cfstream_data->cancelSource = CFRunLoopSourceCreate(NULL, 0, &cfstream_data->cancelContext); r = low_open(s); if (r < 0) { mailstream_low_cfstream_close(s); return NULL; } return s; #else return NULL; #endif }
/* MySimpleDownload implements the download command. It sets up a MyStreamInfo 'object' with the read stream being an FTP stream of the file to download and the write stream being a file stream of the destination file. It then returns, and the real work happens asynchronously in the runloop. The function returns true if the stream setup succeeded, and false if it failed. */ static Boolean MySimpleDownload(CFStringRef urlString, CFURLRef destinationFolder, CFStringRef username, CFStringRef password) { CFReadStreamRef readStream; CFWriteStreamRef writeStream; CFStreamClientContext context = { 0, NULL, NULL, NULL, NULL }; CFURLRef downloadPath, downloadURL; CFStringRef fileName; Boolean dirPath, success = true; MyStreamInfo *streamInfo; assert(urlString != NULL); assert(destinationFolder != NULL); assert( (username != NULL) || (password == NULL) ); /* Returns true if the CFURL path represents a directory. */ dirPath = CFURLHasDirectoryPath(destinationFolder); if (!dirPath) { fprintf(stderr, "Download destination must be a directory.\n"); return false; } /* Create a CFURL from the urlString. */ downloadURL = CFURLCreateWithString(kCFAllocatorDefault, urlString, NULL); assert(downloadURL != NULL); /* Copy the end of the file path and use it as the file name. */ fileName = CFURLCopyLastPathComponent(downloadURL); assert(fileName != NULL); /* Create the downloadPath by taking the destination folder and appending the file name. */ downloadPath = CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault, destinationFolder, fileName, false); assert(downloadPath != NULL); CFRelease(fileName); /* Create a CFWriteStream for the file being downloaded. */ writeStream = CFWriteStreamCreateWithFile(kCFAllocatorDefault, downloadPath); assert(writeStream != NULL); CFRelease(downloadPath); /* CFReadStreamCreateWithFTPURL creates an FTP read stream for downloading from an FTP URL. */ readStream = CFReadStreamCreateWithFTPURL(kCFAllocatorDefault, downloadURL); assert(readStream != NULL); CFRelease(downloadURL); /* Initialize our MyStreamInfo structure, which we use to store some information about the stream. */ MyStreamInfoCreate(&streamInfo, readStream, writeStream); context.info = (void *)streamInfo; /* CFWriteStreamOpen will return success/failure. Opening a stream causes it to reserve all the system resources it requires. If the stream can open non-blocking, this will always return TRUE; listen to the run loop source to find out when the open completes and whether it was successful. */ success = CFWriteStreamOpen(writeStream); if (success) { /* CFReadStreamSetClient registers a callback to hear about interesting events that occur on a stream. */ success = CFReadStreamSetClient(readStream, kNetworkEvents, MyDownloadCallBack, &context); if (success) { /* Schedule a run loop on which the client can be notified about stream events. The client callback will be triggered via the run loop. It's the caller's responsibility to ensure that the run loop is running. */ CFReadStreamScheduleWithRunLoop(readStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); MyCFStreamSetUsernamePassword(readStream, username, password); MyCFStreamSetFTPProxy(readStream, &streamInfo->proxyDict); /* Setting the kCFStreamPropertyFTPFetchResourceInfo property will instruct the FTP stream to fetch the file size before downloading the file. Note that fetching the file size adds some time to the length of the download. Fetching the file size allows you to potentially provide a progress dialog during the download operation. You will retrieve the actual file size after your CFReadStream Callback gets called with a kCFStreamEventOpenCompleted event. */ CFReadStreamSetProperty(readStream, kCFStreamPropertyFTPFetchResourceInfo, kCFBooleanTrue); /* CFReadStreamOpen will return success/failure. Opening a stream causes it to reserve all the system resources it requires. If the stream can open non-blocking, this will always return TRUE; listen to the run loop source to find out when the open completes and whether it was successful. */ success = CFReadStreamOpen(readStream); if (success == false) { fprintf(stderr, "CFReadStreamOpen failed\n"); MyStreamInfoDestroy(streamInfo); } } else { fprintf(stderr, "CFReadStreamSetClient failed\n"); MyStreamInfoDestroy(streamInfo); } } else { fprintf(stderr, "CFWriteStreamOpen failed\n"); MyStreamInfoDestroy(streamInfo); } return success; }
/* extern */ Boolean HttpContextOpen(HttpContextRef context) { do { Boolean didSet; CFRunLoopRef runLoop = CFRunLoopGetCurrent(); CFStreamClientContext streamCtxt = {0, context, (void*(*)(void*))&HttpContextRetain, (void(*)(void*))&HttpContextRelease, NULL}; CFRunLoopTimerContext timerCtxt = {0, context, (const void*(*)(const void*))&HttpContextRetain, (void(*)(const void*))&HttpContextRelease, NULL}; // Set the client on the read stream. didSet = CFReadStreamSetClient(context->_inStream, kReadEvents, (CFReadStreamClientCallBack)&_ReadStreamCallBack, &streamCtxt); // Fail if unable to set the client. if (!didSet) break; // Set the client on the write stream. didSet = CFWriteStreamSetClient(context->_outStream, kWriteEvents, (CFWriteStreamClientCallBack)&_WriteStreamCallBack, &streamCtxt); // Fail if unable to set the client. if (!didSet) break; // Schedule the streams on the current run loop and default mode. CFReadStreamScheduleWithRunLoop(context->_inStream, runLoop, kCFRunLoopCommonModes); CFWriteStreamScheduleWithRunLoop(context->_outStream, runLoop, kCFRunLoopCommonModes); // Open the stream for reading. if (!CFReadStreamOpen(context->_inStream)) break; // Open the stream for writing. if (!CFWriteStreamOpen(context->_outStream)) break; // Create the timeout timer context->_timer = CFRunLoopTimerCreate(CFGetAllocator(context->_inStream), CFAbsoluteTimeGetCurrent() + kTimeOutInSeconds, 0, // interval 0, // flags 0, // order (CFRunLoopTimerCallBack)_TimerCallBack, &timerCtxt); // Fail if unable to create the timer. if (context->_timer == NULL) break; CFRunLoopAddTimer(runLoop, context->_timer, kCFRunLoopCommonModes); return TRUE; } while (0); // Something failed, so clean up. HttpContextClose(context); return FALSE; }
int tnet_transport_wrap(tnet_transport_t *transport, int index) { transport_context_t *context = transport->context; transport_socket_t *sock = context->sockets[index]; // If the socket is already wrapped in a CFSocket then return. if (sock->cf_socket || sock->cf_read_stream) { return 1; } // Put a reference to the transport context const CFSocketContext socket_context = { 0, transport, NULL, NULL, NULL }; if (TNET_SOCKET_TYPE_IS_DGRAM(sock->type)) { // Create a CFSocket from the native socket and register for Read events sock->cf_socket = CFSocketCreateWithNative(kCFAllocatorDefault, sock->fd, kCFSocketReadCallBack, &__CFSocketCallBack, &socket_context); // Don't close the socket if the CFSocket is invalidated CFOptionFlags flags = CFSocketGetSocketFlags(sock->cf_socket); flags = flags & ~kCFSocketCloseOnInvalidate; CFSocketSetSocketFlags(sock->cf_socket, flags); // Create a new RunLoopSource and register it with the main thread RunLoop sock->cf_run_loop_source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sock->cf_socket, 0); CFRunLoopAddSource(context->cf_run_loop, sock->cf_run_loop_source, kCFRunLoopDefaultMode); CFRelease(sock->cf_run_loop_source); } else if (TNET_SOCKET_TYPE_IS_STREAM(sock->type)) { // Create a pair of streams (read/write) from the socket CFStreamCreatePairWithSocket(kCFAllocatorDefault, sock->fd, &sock->cf_read_stream, &sock->cf_write_stream); // Don't close underlying socket CFReadStreamSetProperty(sock->cf_read_stream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse); CFWriteStreamSetProperty(sock->cf_write_stream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse); if (TNET_SOCKET_TYPE_IS_SECURE(sock->type)) { CFMutableDictionaryRef settings = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionaryAddValue(settings, kCFStreamSSLAllowsExpiredCertificates, kCFBooleanTrue); CFDictionaryAddValue(settings, kCFStreamSSLAllowsAnyRoot, kCFBooleanTrue); CFDictionaryAddValue(settings, kCFStreamSSLValidatesCertificateChain, kCFBooleanFalse); CFDictionaryAddValue(settings, kCFStreamSSLPeerName, kCFNull); // Set the SSL settings CFReadStreamSetProperty(sock->cf_read_stream, kCFStreamPropertySocketSecurityLevel, kCFStreamSocketSecurityLevelNegotiatedSSL); CFReadStreamSetProperty(sock->cf_read_stream, kCFStreamPropertySSLSettings, settings); CFWriteStreamSetProperty(sock->cf_write_stream, kCFStreamPropertySocketSecurityLevel, kCFStreamSocketSecurityLevelNegotiatedSSL); CFWriteStreamSetProperty(sock->cf_write_stream, kCFStreamPropertySSLSettings, settings); CFRelease(settings); } #if __IPHONE_4_0 // Mark the stream for VoIP usage CFReadStreamSetProperty(sock->cf_read_stream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); CFWriteStreamSetProperty(sock->cf_write_stream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); #endif // Setup a context for the streams CFStreamClientContext streamContext = { 0, transport, NULL, NULL, NULL }; // Set the client callback for the stream CFReadStreamSetClient(sock->cf_read_stream, kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, &__CFReadStreamClientCallBack, &streamContext); CFWriteStreamSetClient(sock->cf_write_stream, kCFStreamEventOpenCompleted | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, &__CFWriteStreamClientCallBack, &streamContext); // Enroll streams in the run-loop CFReadStreamScheduleWithRunLoop(sock->cf_read_stream, context->cf_run_loop, kCFRunLoopDefaultMode); CFWriteStreamScheduleWithRunLoop(sock->cf_write_stream, context->cf_run_loop, kCFRunLoopDefaultMode); // Release references CFRelease(sock->cf_read_stream); CFRelease(sock->cf_write_stream); CFReadStreamOpen(sock->cf_read_stream); CFWriteStreamOpen(sock->cf_write_stream); } return 0; }