Exemplo n.º 1
0
int read_plist(char *plpath, CFDictionaryRef *dr) {
  CFURLRef cfurl = NULL;
  CFReadStreamRef cfrs = NULL;
  CFDictionaryRef cfdict = NULL;
  CFPropertyListFormat fmt = kCFPropertyListXMLFormat_v1_0;
  CFStreamError err;

  int rc = 0;
  char respath[MAXPATHLEN];

  if (plpath == NULL) {
    fprintf(stderr, "%s: Invalid plist path\n", __FUNCTION__);
    return (-1);
  }

  if (realpath(plpath, respath) == NULL) {
    fprintf(stderr, "%s: realpath failed: %s\n", __FUNCTION__, strerror(errno));
    return (-1);
  }

  /*
   * must convert C string path to CFURL to read the plist
   * from disk. no convenience methods here like Cocoa's
   * -dictionaryWithContentsOfFile:
   */
  if ((cfurl = CFURLCreateFromFileSystemRepresentation(
           kCFAllocatorDefault, (const UInt8 *)respath,
           (CFIndex)strlen(respath), false)) == NULL) {
    fprintf(stderr, "%s: failed to create URL for %s\n", __FUNCTION__, respath);
    return (-1);
  }

  if ((cfrs = CFReadStreamCreateWithFile(kCFAllocatorDefault, cfurl)) == NULL) {
    fprintf(stderr, "%s: failed to create read stream\n", __FUNCTION__);
    rc = -1;
    goto cleanup;
  }
  if (CFReadStreamOpen(cfrs) == false) {
    err = CFReadStreamGetError(cfrs);
    fprintf(stderr, "%s: failed to open read stream\n", __FUNCTION__);
    if (err.domain == kCFStreamErrorDomainPOSIX) {
      fprintf(stderr, "%s: %s\n", plpath, strerror(errno));
    } else {
      fprintf(stderr, "domain %d, error %d\n", (int)err.domain, (int)err.error);
    }
    rc = -1;
    goto cleanup;
  }

  if ((cfdict = CFPropertyListCreateFromStream(kCFAllocatorDefault, cfrs, 0,
                                               kCFPropertyListImmutable, &fmt,
                                               NULL)) == NULL) {
    fprintf(stderr, "%s: failed to read plist\n", __FUNCTION__);
    rc = -1;
    goto cleanup;
  }

  if (!CFPropertyListIsValid(cfdict, fmt)) {
    fprintf(stderr, "%s: invalid plist\n", plpath);
    CFRelease(cfdict);
    cfdict = NULL;
    rc = -1;
  }

cleanup:
  if (cfurl != NULL) {
    CFRelease(cfurl);
  }
  if (cfrs != NULL) {
    CFReadStreamClose(cfrs);
    CFRelease(cfrs);
  }

  *dr = cfdict;

  return (rc);
}
Exemplo n.º 2
0
void SocketStreamHandle::readStreamCallback(CFStreamEventType type)
{
    switch(type) {
    case kCFStreamEventNone:
        break;
    case kCFStreamEventOpenCompleted:
        break;
    case kCFStreamEventHasBytesAvailable: {
        if (m_connectingSubstate == WaitingForConnect) {
            if (m_connectionType == CONNECTProxy) {
                RetainPtr<CFHTTPMessageRef> proxyResponse(AdoptCF, wkCopyCONNECTProxyResponse(m_readStream.get(), m_httpsURL.get()));
                if (proxyResponse && (407 == CFHTTPMessageGetResponseStatusCode(proxyResponse.get()))) {
                    addCONNECTCredentials(proxyResponse.get());
                    return;
                }
            }
        } else 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);
            if (m_state == Closed)
                break;
            // Fall through.
        } else if (m_state == Closed)
            break;

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

        CFIndex length;
        UInt8 localBuffer[1024]; // Used if CFReadStreamGetBuffer couldn't return anything.
        const UInt8* ptr = CFReadStreamGetBuffer(m_readStream.get(), 0, &length);
        if (!ptr) {
            length = CFReadStreamRead(m_readStream.get(), localBuffer, sizeof(localBuffer));
            ptr = localBuffer;
        }

        m_client->didReceiveData(this, reinterpret_cast<const char*>(ptr), length);

        break;
    }
    case kCFStreamEventCanAcceptBytes:
        ASSERT_NOT_REACHED();
        break;
    case kCFStreamEventErrorOccurred: {
#ifndef BUILDING_ON_TIGER
        RetainPtr<CFErrorRef> error(AdoptCF, CFReadStreamCopyError(m_readStream.get()));
        reportErrorToClient(error.get());
#else
        CFStreamError error = CFReadStreamGetError(m_readStream.get());
        m_client->didFail(this, SocketStreamError(error.error)); // FIXME: Provide a sensible error.
#endif
        break;
    }
    case kCFStreamEventEndEncountered:
        platformClose();
        break;
    }
}
static void perform_upload_request__string(
    SG_context* pCtx,
    CFHTTPMessageRef myRequest,
    SG_pathname* pPath,
    CFHTTPMessageRef* pmyResponse,
    SG_string** ppstr
)
{
    CFReadStreamRef myReadStream = NULL;
    CFHTTPMessageRef myResponse = NULL;
    SG_string* pstr = NULL;
    CFReadStreamRef upload = NULL;
    CFURLRef upload_file_url = NULL;

    // set the content-length header
    {
        SG_uint64 len = 0;
        SG_ERR_CHECK(  SG_fsobj__length__pathname(pCtx, pPath, &len, NULL)  );

        CFStringRef headerFieldName = CFSTR("Content-Length");
        CFStringRef headerFieldValue = CFStringCreateWithFormat (kCFAllocatorDefault, NULL,  CFSTR("%d"), len);
        CFHTTPMessageSetHeaderFieldValue(myRequest, headerFieldName, headerFieldValue);
        CFRelease(headerFieldValue);
    }

    upload_file_url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8*) SG_pathname__sz(pPath), SG_STRLEN(SG_pathname__sz(pPath)), SG_FALSE);
    upload = CFReadStreamCreateWithFile(kCFAllocatorDefault, upload_file_url);
    CFRelease(upload_file_url);
    if (!CFReadStreamOpen(upload))
    {
        CFStreamError myErr = CFReadStreamGetError(upload);

        if (myErr.domain == kCFStreamErrorDomainPOSIX)
        {
            // Interpret myErr.error as a UNIX errno.
            SG_ERR_THROW(  SG_ERR_ERRNO(myErr.error)  );
        }
        else if (myErr.domain == kCFStreamErrorDomainMacOSStatus)
        {
            // Interpret myErr.error as a MacOS error code.
            // TODO SG_ERR_THROW(  SG_ERR_MAC((OSStatus) myErr.error)  );
            SG_ERR_THROW(  SG_ERR_UNSPECIFIED  );
        }
    }

    SG_ERR_CHECK(  send_upload_request(pCtx, myRequest, upload, &myReadStream)  );
    SG_ERR_CHECK(  read_entire_stream__string(pCtx, myReadStream, &pstr, &myResponse)  );

    *ppstr = pstr;
    pstr = NULL;

    *pmyResponse = myResponse;
    myResponse = NULL;

fail:
    if (upload)
    {
        CFRelease(upload);
    }
    if (myReadStream)
    {
        CFReadStreamClose(myReadStream);
        CFRelease(myReadStream);
        myReadStream = NULL;
    }

    if (myResponse)
    {
        CFRelease(myResponse);
        myResponse = NULL;
    }

    SG_STRING_NULLFREE(pCtx, pstr);
}
static void read_entire_stream__string(
    SG_context* pCtx,
    CFReadStreamRef myReadStream,
    SG_string** ppstr,
    CFHTTPMessageRef* pp
)
{
    SG_string* pstr = NULL;
    CFHTTPMessageRef myResponse = NULL;
    CFIndex numBytesRead = 0;

    SG_ERR_CHECK(  SG_string__alloc__sz(pCtx, &pstr, "")  );
    do
    {
        UInt8 buf[8192]; // TODO
        numBytesRead = CFReadStreamRead(myReadStream, buf, sizeof(buf));
        if( numBytesRead > 0 )
        {
            SG_ERR_CHECK(  SG_string__append__buf_len(pCtx, pstr, buf, numBytesRead)  );

            if (!myResponse)
            {
                myResponse = (CFHTTPMessageRef)CFReadStreamCopyProperty(myReadStream, kCFStreamPropertyHTTPResponseHeader);
            }
        }
        else if( numBytesRead < 0 )
        {
            CFStreamError myErr = CFReadStreamGetError(myReadStream);
            // TODO clean this up
            if (myErr.domain == kCFStreamErrorDomainPOSIX)
            {
                if (ETIMEDOUT == myErr.error)
                {
                    usleep(5000);
                    numBytesRead = 0;
                }
                else
                {
                    // Interpret myErr.error as a UNIX errno.
                    SG_ERR_THROW(  SG_ERR_ERRNO(myErr.error)  );
                }
            }
            else if (myErr.domain == kCFStreamErrorDomainMacOSStatus)
            {
                // Interpret myErr.error as a MacOS error code.
                // TODO SG_ERR_THROW(  SG_ERR_MAC((OSStatus) myErr.error)  );
                SG_ERR_THROW(  SG_ERR_UNSPECIFIED  );
            }
        }
    } while( numBytesRead > 0 );

    if (!myResponse)
    {
        myResponse = (CFHTTPMessageRef)CFReadStreamCopyProperty(myReadStream, kCFStreamPropertyHTTPResponseHeader);
    }

    *pp = myResponse;
    myResponse = NULL;

    *ppstr = pstr;
    pstr = NULL;

fail:
    if (myResponse)
    {
        CFRelease(myResponse);
    }
    SG_STRING_NULLFREE(pCtx, pstr);
}
static void read_entire_stream__file(
    SG_context* pCtx,
    CFReadStreamRef myReadStream,
    SG_pathname* pPath,
    CFHTTPMessageRef* pp,
    SG_bool b_progress
)
{
    CFHTTPMessageRef myResponse = NULL;
    CFIndex numBytesRead = 0;
    SG_file* pFile = NULL;
    SG_int64 content_length = 0;
    SG_int64 so_far = 0;

    SG_ERR_CHECK(  SG_file__open__pathname(pCtx, pPath, SG_FILE_CREATE_NEW | SG_FILE_WRONLY, 0644, &pFile)  );
    do
    {
        UInt8 buf[8192]; // TODO
        numBytesRead = CFReadStreamRead(myReadStream, buf, sizeof(buf));
        if( numBytesRead > 0 )
        {
            SG_ERR_CHECK(  SG_file__write(pCtx, pFile, numBytesRead, buf, NULL)  );
            if (!myResponse)
            {
                myResponse = (CFHTTPMessageRef)CFReadStreamCopyProperty(myReadStream, kCFStreamPropertyHTTPResponseHeader);
                CFStringRef contentLengthString = CFHTTPMessageCopyHeaderFieldValue(myResponse, CFSTR("Content-Length"));
                if (contentLengthString)
                {
                    // TODO 32 bit limit problem here
                    content_length = CFStringGetIntValue(contentLengthString);
                    CFRelease(contentLengthString);
                }
                if (b_progress)
                {
                    SG_ERR_CHECK(  SG_log__set_steps(pCtx, content_length / 1024, "KB")  );
                }
            }
            so_far += (SG_uint32) numBytesRead;
            if (b_progress)
            {
                SG_ERR_CHECK(  SG_log__set_finished(pCtx, so_far / 1024)  );
            }
        }
        else if( numBytesRead < 0 )
        {
            CFStreamError myErr = CFReadStreamGetError(myReadStream);
            // TODO clean this up
            if (myErr.domain == kCFStreamErrorDomainPOSIX)
            {
                if (ETIMEDOUT == myErr.error)
                {
                    usleep(5000);
                    numBytesRead = 0;
                }
                else
                {
                    // Interpret myErr.error as a UNIX errno.
                    SG_ERR_THROW(  SG_ERR_ERRNO(myErr.error)  );
                }
            }
            else if (myErr.domain == kCFStreamErrorDomainMacOSStatus)
            {
                // Interpret myErr.error as a MacOS error code.
                // TODO SG_ERR_THROW(  SG_ERR_MAC((OSStatus) myErr.error)  );
                SG_ERR_THROW(  SG_ERR_UNSPECIFIED  );
            }
        }
    } while( numBytesRead > 0 );

    SG_ERR_CHECK(  SG_file__close(pCtx, &pFile)  );

    if (!myResponse)
    {
        myResponse = (CFHTTPMessageRef)CFReadStreamCopyProperty(myReadStream, kCFStreamPropertyHTTPResponseHeader);
    }

    *pp = myResponse;
    myResponse = NULL;

fail:
    if (pFile)
    {
        SG_ERR_CHECK(  SG_file__close(pCtx, &pFile)  );
        // TODO delete it too
    }
    if (myResponse)
    {
        CFRelease(myResponse);
    }
}
Exemplo n.º 6
0
/* MyDirectoryListingCallBack is the stream callback for the CFFTPStream during a directory 
list operation. Its main purpose is to read bytes off the FTP stream, which is returning bytes 
of the directory listing, parse them, and 'pretty' print the resulting directory entries. */
static void
MyDirectoryListingCallBack(CFReadStreamRef readStream, CFStreamEventType type, void * clientCallBackInfo)
{
    MyStreamInfo     *info = (MyStreamInfo *)clientCallBackInfo;
    CFIndex          bytesRead;
    CFStreamError    error;
    CFDictionaryRef  parsedDict;
    
    assert(readStream != NULL);
    assert(info       != NULL);
    assert(info->readStream == readStream);

    switch (type) {

        case kCFStreamEventOpenCompleted:
            fprintf(stderr, "Open complete\n");
            break;
        case kCFStreamEventHasBytesAvailable:
        
            /* When we get here, there are bytes to be read from the stream.  There are two cases:
            either info->leftOverByteCount is zero, in which case we complete processed the last 
            buffer full of data (or we're at the beginning of the listing), or 
            info->leftOverByteCount is non-zero, in which case there are that many bytes at the 
            start of info->buffer that were left over from the last time that we were called. 
            By definition, any left over bytes were insufficient to form a complete directory 
            entry.
            
            In both cases, we just read the next chunk of data from the directory listing stream 
            and append it to our buffer.  We then process the buffer to see if it now contains 
            any complete directory entries. */

            /* 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 + info->leftOverByteCount, kMyBufferSize - info->leftOverByteCount);
            if (bytesRead > 0) {
                const UInt8 *   nextByte;
                CFIndex         bytesRemaining;
                CFIndex         bytesConsumedThisTime;

                /* Parse directory entries from the buffer until we either run out of bytes 
                or we stop making forward progress (indicating that the buffer does not have 
                enough bytes of valid data to make a complete directory entry). */

                nextByte       = info->buffer;
                bytesRemaining = bytesRead + info->leftOverByteCount;
                do
                {                    

                    /* CFFTPCreateParsedResourceListing parses a line of file or folder listing
                    of Unix format, and stores the extracted result in a CFDictionary. */
                    bytesConsumedThisTime = CFFTPCreateParsedResourceListing(NULL, nextByte, bytesRemaining, &parsedDict);
                    if (bytesConsumedThisTime > 0) {

                        /* It is possible for CFFTPCreateParsedResourceListing to return a positive number 
                        but not create a parse dictionary.  For example, if the end of the listing text 
                        contains stuff that can't be parsed, CFFTPCreateParsedResourceListing returns 
                        a positive number (to tell the calle that it's consumed the data), but doesn't 
                        create a parse dictionary (because it couldn't make sens of the data).
                        So, it's important that we only try to print parseDict if it's not NULL. */
                        
                        if (parsedDict != NULL) {
                            MyPrintDirectoryListing(parsedDict);
                            CFRelease(parsedDict);
                        }

                        nextByte       += bytesConsumedThisTime;
                        bytesRemaining -= bytesConsumedThisTime;

                    } else if (bytesConsumedThisTime == 0) {
                        /* This should never happen because we supply a pretty large buffer. 
                        Still, we handle it by leaving the loop, which leaves the remaining 
                        bytes in the buffer. */
                    } else if (bytesConsumedThisTime == -1) {
                        fprintf(stderr, "CFFTPCreateParsedResourceListing parse failure\n");
                        goto exit;
                    }

                } while ( (bytesRemaining > 0) && (bytesConsumedThisTime > 0) );
                
                /* If any bytes were left over, leave them in the buffer for next time. */
                if (bytesRemaining > 0) {
                    memmove(info->buffer, nextByte, bytesRemaining);                    
                }
                info->leftOverByteCount = bytesRemaining;
            } else {
                /* If bytesRead < 0, we've hit an error.  If bytesRead == 0, we've hit the end of the 
                directory listing.  In either case, we do nothing, and rely on CF to call us with 
                kCFStreamEventErrorOccurred or kCFStreamEventEndEncountered in order for us to do our 
                clean up. */
            }
            break;
        case kCFStreamEventErrorOccurred:
            error = CFReadStreamGetError(info->readStream);
            fprintf(stderr, "CFReadStreamGetError returned (%ld, %ld)\n", error.domain, error.error);
            goto exit;
        case kCFStreamEventEndEncountered:
            fprintf(stderr, "Listing complete\n");
            goto exit;
        default:
            fprintf(stderr, "Received unexpected CFStream event (%ld)", type);
            break;
    }
    return;

exit:
    MyStreamInfoDestroy(info);
    CFRunLoopStop(CFRunLoopGetCurrent());
    return;
}
Exemplo n.º 7
0
/* MyDownloadCallBack is the stream callback for the CFFTPStream during a download operation. 
Its main purpose is to read bytes off the FTP stream for the file being downloaded and write 
them to the file stream of the destination file. */
static void
MyDownloadCallBack(CFReadStreamRef readStream, CFStreamEventType type, void * clientCallBackInfo)
{
    MyStreamInfo      *info = (MyStreamInfo *)clientCallBackInfo;
    CFIndex           bytesRead = 0, bytesWritten = 0;
    CFStreamError     error;
    CFNumberRef       cfSize;
    SInt64            size;
    float             progress;
    
    assert(readStream != NULL);
    assert(info       != NULL);
    assert(info->readStream == readStream);

    switch (type) {

        case kCFStreamEventOpenCompleted:
            /* Retrieve the file size from the CFReadStream. */
            cfSize = CFReadStreamCopyProperty(info->readStream, kCFStreamPropertyFTPResourceSize);
            
            fprintf(stderr, "Open complete\n");
            
            if (cfSize) {
                if (CFNumberGetValue(cfSize, kCFNumberSInt64Type, &size)) {
                    fprintf(stderr, "File size is %" PRId64 "\n", size);
                    info->fileSize = size;
                }
                CFRelease(cfSize);
            } else {
                fprintf(stderr, "File size is unknown\n");
                assert(info->fileSize == 0);            // It was set up this way by MyStreamInfoCreate.
            }
            break;
        case kCFStreamEventHasBytesAvailable:

            /* 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) {
                /* Just in case we call CFWriteStreamWrite and it returns without writing all
                the data, we loop until all the data is written successfully.  Since we're writing
                to the "local" file system, it's unlikely that CFWriteStreamWrite will return before
                writing all the data, but it would be bad if we simply exited the callback because
                we'd be losing some of the data that we downloaded. */
                bytesWritten = 0;
                while (bytesWritten < bytesRead) {
                    CFIndex result;

                    result = CFWriteStreamWrite(info->writeStream, info->buffer + bytesWritten, bytesRead - bytesWritten);
                    if (result <= 0) {
                        fprintf(stderr, "CFWriteStreamWrite returned %ld\n", result);
                        goto exit;
                    }
                    bytesWritten += result;
                }
                info->totalBytesWritten += bytesWritten;
            } else {
                /* If bytesRead < 0, we've hit an error.  If bytesRead == 0, we've hit the end of the file.  
                In either case, we do nothing, and rely on CF to call us with kCFStreamEventErrorOccurred 
                or kCFStreamEventEndEncountered in order for us to do our clean up. */
            }
            
            if (info->fileSize > 0) {
                progress = 100*((float)info->totalBytesWritten/(float)info->fileSize);
                fprintf(stderr, "\r%.0f%%", progress);
            }
            break;
        case kCFStreamEventErrorOccurred:
            error = CFReadStreamGetError(info->readStream);
            fprintf(stderr, "CFReadStreamGetError returned (%ld, %ld)\n", error.domain, error.error);
            goto exit;
        case kCFStreamEventEndEncountered:
            fprintf(stderr, "\nDownload complete\n");
            goto exit;
        default:
            fprintf(stderr, "Received unexpected CFStream event (%ld)", type);
            break;
    }
    return;
    
exit:    
    MyStreamInfoDestroy(info);
    CFRunLoopStop(CFRunLoopGetCurrent());
    return;
}